diff --git a/.gitignore b/.gitignore index 8831c0ac..4d3a6923 100644 --- a/.gitignore +++ b/.gitignore @@ -36,8 +36,5 @@ # generated files from test runs ross.csv - -install-mastiff/include/codes/model-net-method.h -configure.ac -configure.ac -configure.ac \ No newline at end of file + +install-mastiff/include/codes/model-net-method.h \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..86b4b5fe --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.10) + +# set the project name and version +project(codes LANGUAGES C CXX VERSION 2.0) + +include(CMakePrintHelpers) +cmake_print_variables(CMAKE_CURRENT_SOURCE_DIR) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src/cmake/") +cmake_print_variables(CMAKE_MODULE_PATH) + +set(CMAKE_INSTALL_PREFIX "${PROJECT_BINARY_DIR}" CACHE PATH "Where to install CODES") + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED True) + +#prevent cmake from stripping the runtime path (important if shared libraries are imported) +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) + +set(ROSS_PKG_CONFIG_PATH "" CACHE PATH "Where is ROSS PKG_CONFIG is installed?") +set(SWM_PKG_CONFIG_PATH "" CACHE PATH "Where is the SWM PKG_CONFIG installed?") +set(ARGOBOTS_PKG_CONFIG_PATH "" CACHE PATH "Where is argobots PKG_COPNFIG installed? Necessary for SWM") +set(DAMARIS_PKG_CONFIG_PATH "" CACHE PATH "Where is the damaris PKG_CONFIG installed?") + + +find_package(PkgConfig REQUIRED) +set(ENV{PKG_CONFIG_PATH} "${ROSS_PKG_CONFIG_PATH}:${SWM_PKG_CONFIG_PATH}:${ARGOBOTS_PKG_CONFIG_PATH}") +pkg_check_modules(ROSS REQUIRED IMPORTED_TARGET ross) + +# MPI +include(SetupMPI) +if(MPI_C_FOUND) + include_directories(${MPI_C_INCLUDE_PATH}) + list(APPEND CODES_EXTERNAL_LIBS ${MPI_C_LIBRARIES}) +else(MPI_C_FOUND) + message("WARNING: Could not find MPI!") + message(" Either add an MPI compiler to your path (using modules)") + message(" Or force CMake to build using the correct compiler (`export CC=mpicc`)") +endif(MPI_C_FOUND) + + +## DUMPI +set(DUMPI_BUILD_PATH "" CACHE PATH "Directory where dumpi include and lib are installed") +find_library(DUMPI_LIB undumpi PATHS ${DUMPI_BUILD_PATH}/lib) +if(NOT DUMPI_LIB) + message(STATUS "Undumpi library not found, DUMPI trace workloads disabled") + unset(USE_DUMPI) +else(DUMPI_LIB) + message(STATUS "Undumpi library found ${DUMPI_LIB}") + set(DUMPI_INCLUDE "${DUMPI_BUILD_PATH}/include" CACHE PATH "Dumpi library include") + set(DUMPI_CFLAGS "-I${DUMPI_INCLUDE}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DUMPI_CFLAGS}") + add_definitions(-DUSE_DUMPI=1) + set(USE_DUMPI true) +endif() + +## SWM +pkg_check_modules(SWM IMPORTED_TARGET swm) +if(NOT SWM_FOUND) + message(STATUS "SWM Library Not Found, Online workloads disabled") +else(SWM_FOUND) + message(STATUS "SWM Library Found: ${SWM_LIBRARIES}") + pkg_check_modules(ARGOBOTS REQUIRED IMPORTED_TARGET argobots) + if(NOT ARGOBOTS_FOUND) + message(STATUS "Argobots Library Not Found, Online workloads disabled") + else(ARGOBOTS_FOUND) + message(STATUS "Argobots Library Found: ${ARGOBOTS_LIBRARIES}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARGOBOTS_CFLAGS} -I${ARGOBOTS_INCLUDE}") + + pkg_get_variable(SWM_DATAROOTDIR swm datarootdir) + cmake_print_variables(SWM_DATAROOTDIR) + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SWM_CFLAGS} -I${SWM_INCLUDE}") + add_definitions(-DUSE_ONLINE=1) + set(USE_ONLINE true) + endif() +endif() + +## RECORDER +option(USE_RECORDER "use recorder io workload" ON) +if(USE_RECORDER) + add_definitions(-DUSE_RECORDER=1) +endif() + +## DARSHAN + + +## DAMARIS +# pkg_check_modules(DAMARIS IMPORTED_TARGET) +# if(NOT DAMARIS_FOUND) +# message(STATUS "DAMARIS Library not found, Damaris disabled") +# else(DAMARIS_FOUND) +# set(USE_DAMARIS true) +# endif() + +cmake_print_variables(CMAKE_C_FLAGS) +add_subdirectory(src) + + +configure_file(codes_config.h.in codes_config.h) + + + diff --git a/README.md b/README.md index 3388fad8..a7d1401a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# *_DEVELOP BRANCH REQUIRES ROSS "`tiebreaker`" BRANCH_* + # CODES Discrete-event Simulation Framework ### [Join our CODES user mailing list](https://mailchi.mp/75d0c8aa42c3/codes-user-group) to stay up to date with major changes, events, and news! diff --git a/codes/codes-workload.h b/codes/codes-workload.h index 44a64bf6..e97ec88c 100644 --- a/codes/codes-workload.h +++ b/codes/codes-workload.h @@ -20,7 +20,7 @@ extern "C" { #include "configuration.h" #ifdef USE_ONLINE -#include +#include "abt.h" #endif #define MAX_NAME_LENGTH_WKLD 512 @@ -173,6 +173,9 @@ enum codes_workload_op_type CODES_WK_MPI_COLL_WRITE, /* collective_read */ CODES_WK_MPI_COLL_READ, + + /* intrumentation */ + CODES_WK_MARK, }; /* I/O operation paramaters */ diff --git a/codes/congestion-controller-core.h b/codes/congestion-controller-core.h new file mode 100644 index 00000000..c10c86c6 --- /dev/null +++ b/codes/congestion-controller-core.h @@ -0,0 +1,89 @@ +#ifndef CONGESTION_CONTROLLER_CORE_H +#define CONGESTION_CONTROLLER_CORE_H + +/** + * congestion-controller.h -- Organizing state and behavior for congestion management + * Neil McGlohon + * + * Copyright (c) 2019 Rensselaer Polytechnic Institute + */ +#include +#include +#define MAX_PATTERN_LEN 32 +#define MAX_PORT_COUNT 256 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int g_congestion_control_enabled; +extern tw_stime g_congestion_control_notif_latency; +extern const tw_optdef cc_app_opt []; + +// Defines congestion (aggregate of stall) +typedef enum congestion_status +{ + UNCONGESTED = 0, + CONGESTED = 1 +} congestion_status; + +typedef enum controller_type +{ + CC_ROUTER = 1, + CC_TERMINAL = 2 +} controller_type; + +/* Enumeration of types of events sent between congestion controllers */ +typedef enum cc_event_t +{ + CC_SIGNAL_NORMAL = 1001, + CC_SIGNAL_ABATE, + CC_BANDWIDTH_CHECK, + CC_SIM_ACK // A 'simulated' ack message sent from receiving terminal to original to let it know that its packet was ejected +} cc_event_t; + +typedef struct congestion_control_message +{ + short type; //type of event + tw_lpid sender_lpid; //lpid of the sender + int app_id; + + // Reverse computation values + double saved_window; + double saved_rate; + double saved_bw; + double saved_new_bw; //for commit + tw_stime msg_time; // for commit + unsigned int saved_ejected_bytes; + int num_cc_rngs; + short to_congest; + short to_decongest; + + short received_new_while_congested; + int saved_term_id; + double saved_expire_time; + + // Dangerous - same LP dynamic RC state -- if this message is to be sent between two LPs, DON'T USE THIS FIELD + size_t size_abated; + size_t size_deabated; + unsigned int* danger_rc_abated; + unsigned int* danger_rc_deabated; +} congestion_control_message; + +extern void congestion_control_register_terminal_lpname(char lp_name[]); +extern void congestion_control_register_router_lpname(char lp_name[]); + +extern int congestion_control_set_jobmap(struct codes_jobmap_ctx *jobmap_ctx, int net_id); +extern int congestion_control_is_jobmap_set(); +extern int congestion_control_get_job_count(); +extern struct codes_jobmap_ctx* congestion_control_get_jobmap(); +extern void congestion_control_notify_rank_completion(tw_lp *lp); +extern void congestion_control_notify_rank_completion_rc(tw_lp *lp); +extern void congestion_control_notify_job_completion(tw_lp *lp, int app_id); +extern void congestion_control_notify_job_completion_rc(tw_lp *lp, int app_id); + +#ifdef __cplusplus +} +#endif + +#endif /* end of include guard */ \ No newline at end of file diff --git a/codes/congestion-controller-model.h b/codes/congestion-controller-model.h new file mode 100644 index 00000000..e8b673b5 --- /dev/null +++ b/codes/congestion-controller-model.h @@ -0,0 +1,207 @@ +#ifndef CONGESTION_CONTROLLER_MODEL_H +#define CONGESTION_CONTROLLER_MODEL_H + +/** + * congestion-controller-model.h -- Organizing state and behavior for congestion management + * this header file differs from congesiton-controller-core.h in that this one has c++ structures + * in so that c++ is used for network models that use it but not CODES core. + * Neil McGlohon + * + * Copyright (c) 2019 Rensselaer Polytechnic Institute + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +/* Port/VC Channel tree structure +* Used to efficiently determine how many packets are currently located on the router +* and to what terminals they originated from. Each node contains a map of terminal ID to +* the number of packets on said router, port, or vc. +* The root of this tree represents a 'router', the next level is ports, the last level is VCs +* This structure is designed to obey the child sum property. The values stored in a parent represents +* the sum of the values of its children +*/ +typedef enum portchan_node_type { + ROOT = 0, + PORT = 1, + VC = 2 +} portchan_node_type; + +class Portchan_node { +private: + portchan_node_type type; //what level of the tree are we? + unsigned long long packet_count; //number of packets on this node and children + bool is_congested; + tw_stime next_possible_normal_time; + set abated_terminals_this_node; + map abated_terminal_child_counter; //maps terminal ID to number of children nodes that it is under abatement on + map term_count_map; //maps terminal ID to number of packets on this node and children + map app_count_map; //maps application ID to number of packets on this node and children + map > app_to_terminal_counter; //maps application ID to a map of terminals from said application and their packet counts on this node and children + vector children; //pointers to children + +public: + Portchan_node(portchan_node_type pnt, int router_radix, int vcs_per_port); + ~Portchan_node(); + unsigned long long get_packet_count(); + unsigned long long get_packet_count_from_term(unsigned int term_id); + unsigned long long get_packet_count_from_app(unsigned int app_id); + unsigned long long get_packet_count_by_port(int port_no); + unsigned long long get_packet_count_by_port_from_term(int port_no, unsigned int term_id); + unsigned long long get_packet_count_by_port_from_app(int port_no, unsigned int app_id); + unsigned long long get_packet_count_by_port_vc(int port_no, int vc_no); + unsigned long long get_packet_count_by_port_vc_from_term(int port_no, int vc_no, unsigned int term_id); + unsigned long long get_packet_count_by_port_vc_from_app(int port_no, int vc_no, unsigned int app_id); + map get_term_count_map(); + map get_app_count_map(); + map get_term_count_map_by_port(int port_no); + map get_app_count_map_by_port(int port_no); + map get_term_count_map_by_port_vc(int port_no, int vc_no); + map get_app_count_map_by_port_vc(int port_no, int vc_no); + map get_term_count_map_from_app(int app_id); + map get_term_count_map_by_port_from_app(int port_no, int app_id); + map get_term_count_map_by_port_vc_from_app(int port_no, int vc_no, int app_id); + bool is_router_congested(); + bool is_port_congested(int port_no); + bool is_port_vc_congested(int port_no, int vc_no); + void set_router_congestion_state(bool is_congested); + void set_port_congestion_state(int port_no, bool is_congested); + void set_port_vc_congested(int port_no, int vc_no, bool is_congested); + void set_next_possible_router_normal_time(tw_stime time); + void set_next_possible_port_normal_time(int port_no, tw_stime time); + void set_next_possible_vc_normal_time(int port_no, int vc_no, tw_stime time); + tw_stime get_next_possible_router_normal_time(); + tw_stime get_next_possible_port_normal_time(int port_no); + tw_stime get_next_possible_vc_normal_time(int port_no, int vc_no); + void mark_abated_terminal(unsigned int term_id); + void mark_abated_terminal(int port_no, unsigned int term_id); + void mark_abated_terminal(int port_no, int vc_no, unsigned int term_id); + void mark_unabated_terminal(unsigned int term_id); + void mark_unabated_terminal(int port_no, unsigned int term_id); + void mark_unabated_terminal(int port_no, int vc_no, unsigned int term_id); + bool is_abated_terminal(unsigned int term_id); + set get_abated_terminals(); + set get_abated_terminals(int port_no); + set get_abated_terminals(int port_no, int vc_no); + void enqueue_packet(unsigned int packet_size, int port_no, int vc_no, unsigned int term_id, unsigned int app_id); + void dequeue_packet(unsigned int packet_size, int port_no, int vc_no, unsigned int term_id, unsigned int app_id); +}; + +typedef struct cc_param +{ + int router_radix; + int router_vc_per_port; + int router_total_buffer_size; + + double terminal_configured_bandwidth; + int chunk_size; + + double single_vc_congestion_threshold; //unused currently + double single_port_congestion_threshold; + double single_router_congestion_threshold; //unused currently + + double single_port_aggressor_usage_threshold; //percentage of current usage belonging to one app before its classified as an aggressor + + double single_vc_decongestion_threshold; //unused currently + double single_port_decongestion_threshold; + double single_router_decongestion_threshold; //unused currently + + double notification_latency; + double minimum_abatement_time; +} cc_param; + +typedef struct rlc_state +{ + cc_param *params; + tw_lp *lp; + + int router_id; + + int* router_vc_sizes_on_each_port; + double* router_bandwidths_on_each_port; + int* workloads_finished_flag_ptr; + + set output_ports; + Portchan_node *packet_counting_tree; +} rlc_state; + +typedef struct tlc_state +{ + cc_param *params; + tw_lp *lp; + + int terminal_id; + int app_id; //needs to be multiple if multiple jobs per terminal can exist. + + int abatement_signal_count; //if > 0, abate, if 0, normal + + unsigned int window_epoch; + unsigned int ejected_packet_bytes; //in current window + double *ejected_rate_windows; + double cur_average_rate; + + bool is_abatement_active; + + int* workloads_finished_flag_ptr; + + double current_injection_bandwidth_coef; +} tlc_state; + +congestion_control_message* cc_msg_rc_storage_create(); +void cc_msg_rc_storage_delete(void * ptr); + +//event method links +void cc_router_local_congestion_event(rlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp); +void cc_router_local_congestion_event_rc(rlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp); +void cc_router_local_congestion_event_commit(rlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp); +void cc_terminal_local_congestion_event(tlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp); +void cc_terminal_local_congestion_event_rc(tlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp); +void cc_terminal_local_congestion_event_commit(tlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp); + + +// ------------ Local controllers ----------------------- +void cc_router_local_controller_init(rlc_state *s, tw_lp *lp, int total_terminals, int router_id, int radix, int num_vcs_per_port, int *vc_sizes, double* bandwidths, int* workload_finished_flag_ptr); +void cc_router_local_controller_add_output_port(rlc_state *s, int port_no); +void cc_router_received_packet(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg); +void cc_router_received_packet_rc(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg); +void cc_router_forwarded_packet(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg); +void cc_router_forwarded_packet_rc(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg); +void cc_router_congestion_check(rlc_state *s, tw_lp *lp, int port_no, int vc_no, congestion_control_message *rc_msg); +void cc_router_congestion_check_rc(rlc_state *s, tw_lp *lp, int port_no, int vc_no, congestion_control_message *rc_msg); +void cc_router_local_controller_finalize(rlc_state *s); + +void cc_terminal_local_controller_init(tlc_state *s, tw_lp *lp, int terminal_id, int* workload_finished_flag_ptr); +void cc_terminal_send_ack(tlc_state *s, tw_lpid original_terminal_lpgid); +void cc_terminal_send_ack_rc(tlc_state *s); +void cc_terminal_receive_ack(tlc_state *s); +void cc_terminal_receive_ack_rc(tlc_state *s); +void cc_terminal_start_abatement(tlc_state *s, congestion_control_message *msg); +void cc_terminal_start_abatement_rc(tlc_state *s, congestion_control_message *msg); +void cc_terminal_end_abatement(tlc_state *s, congestion_control_message *msg); +void cc_terminal_end_abatement_rc(tlc_state *s, congestion_control_message *msg); +void cc_terminal_receive_normal_signal(tlc_state *s, congestion_control_message *msg); +void cc_terminal_receive_normal_signal_rc(tlc_state *s, congestion_control_message *msg); +void cc_terminal_receive_abatement_signal(tlc_state *s, congestion_control_message *msg); +void cc_terminal_receive_abatement_signal_rc(tlc_state *s, congestion_control_message *msg); +void cc_terminal_process_bandwidth_check(tlc_state *s, congestion_control_message *msg); +void cc_terminal_process_bandwidth_check_rc(tlc_state *s, congestion_control_message *msg); + +double cc_terminal_get_current_injection_bandwidth_coef(tlc_state *s); +bool cc_terminal_is_abatement_active(tlc_state *s); + + +/************* LP Definition **************************************/ + + + + +#endif /* end of include guard */ \ No newline at end of file diff --git a/codes/connection-manager.h b/codes/connection-manager.h deleted file mode 100644 index 09cbe9ec..00000000 --- a/codes/connection-manager.h +++ /dev/null @@ -1,225 +0,0 @@ -#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 -#include -#include -#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 = 2, - CONN_TERMINAL = 3 -}; - -/** - * @brief Struct for connection information. - */ -struct Connection -{ - int port; //port ID of the connection - 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 - ConnectionType conn_type; //type of the connection: CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL -}; - -inline bool operator<(const Connection& lhs, const Connection& rhs) -{ - return lhs.port < rhs.port; -} - -/** - * @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. - * - * @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 - * This class assumes that each router group has the same number of routers in it: _num_routers_per_group. - */ -class ConnectionManager { - 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 - - map< int, Connection > _portMap; //Mapper for ports to connections - - vector< int > _other_groups_i_connect_to; - set< int > _other_groups_i_connect_to_set; - - map< int, vector< Connection > > _connections_to_groups_map; //maps group ID to connections to said group - map< int, vector< Connection > > _all_conns_by_type_map; - - // 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 - - 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 - * @param dest_gid the global ID of the destination router - * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL - */ - void add_connection(int dest_gid, ConnectionType type); - - // /** - // * @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) - - /** - * @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 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); - - /** - * @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); - - /** - * @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 - */ - vector< Connection > get_connections_to_gid(int dest_id, ConnectionType type); - - /** - * @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); - - /** - * @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); - - /** - * @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(); - - /** - * - */ - void solidify_connections(); - - /** - * @brief prints out the state of the connection manager - */ - void print_connections(); -}; - -//implementation found in util/connection-manager.C - -#endif /* end of include guard:*/ \ No newline at end of file diff --git a/codes/model-net-lp.h b/codes/model-net-lp.h index 5b9ca93a..f713caaa 100644 --- a/codes/model-net-lp.h +++ b/codes/model-net-lp.h @@ -32,6 +32,7 @@ extern "C" { #include "net/simplep2p.h" #include "net/torus.h" #include "net/express-mesh.h" +#include "codes/congestion-controller-core.h" extern int model_net_base_magic; @@ -101,6 +102,22 @@ void model_net_method_idle_event2(tw_stime offset_ts, int is_recv_queue, // NOTE: this should ONLY be called on model-net implementations, nowhere else void * model_net_method_get_edata(int net_id, void * msg); +int model_net_method_end_sim_broadcast( + tw_stime offset_ts, + tw_lp *sender); + +tw_event* model_net_method_end_sim_notification( + tw_lpid dest_gid, + tw_stime offset_ts, + tw_lp *sender); + +// Wrapper for congestion controller to request congestion data from destination +tw_event* model_net_method_congestion_event(tw_lpid dest_gid, + tw_stime offset_ts, + tw_lp *sender, + void **msg_data, + void **extra_data); + /// The following functions/data structures should not need to be used by /// model developers - they are just provided so other internal components can /// use them @@ -112,7 +129,12 @@ enum model_net_base_event_type { // gather a sample from the underlying model MN_BASE_SAMPLE, // message goes directly down to topology-specific event handler - MN_BASE_PASS + MN_BASE_PASS, + /* message goes directly to topology-specific event handler for ending the simulation + usefull if there is an infinite heartbeat pattern */ + MN_BASE_END_NOTIF, + // message calls congestion request method on topology specific handler + MN_CONGESTION_EVENT }; typedef struct model_net_base_msg { @@ -142,6 +164,7 @@ typedef struct model_net_wrap_msg { sp_message m_sp2p; // simplep2p nodes_message m_torus; // torus em_message m_em; // express-mesh + congestion_control_message m_cc; // add new ones here } msg; } model_net_wrap_msg; diff --git a/codes/model-net-method.h b/codes/model-net-method.h index ae4808c2..fdf09557 100644 --- a/codes/model-net-method.h +++ b/codes/model-net-method.h @@ -65,6 +65,11 @@ struct model_net_method final_f mn_sample_fini_fn; void (*mn_model_stat_register)(st_model_types *base_type); const st_model_types* (*mn_get_model_stat_types)(); + event_f mn_end_notif_fn; + revent_f mn_end_notif_rc_fn; + event_f cc_congestion_event_fn; + revent_f cc_congestion_event_rc_fn; + commit_f cc_congestion_event_commit_fn; }; extern struct model_net_method * method_array[]; diff --git a/codes/model-net.h b/codes/model-net.h index 772e2072..577ae5ae 100644 --- a/codes/model-net.h +++ b/codes/model-net.h @@ -27,7 +27,7 @@ extern "C" { #define MAX_NAME_LENGTH 256 #define CATEGORY_NAME_MAX 16 -#define CATEGORY_MAX 12 +#define CATEGORY_MAX 15 // simple deprecation attribute hacking #if !defined(DEPRECATED) @@ -38,6 +38,13 @@ extern "C" { # endif #endif +/* Global declarations for configurations that might want to be passed via + * command line in addition to configuration file. Needed a globally accessible + * place for these +*/ +extern char g_nm_link_failure_filepath[]; //filepath to link failure file for use by models that use NetworkManager + + /* HACK: there is currently no scheduling fidelity across multiple * model_net_event calls. Hence, problems arise when some LP sends multiple * messages as part of an event and expects FCFS ordering. A proper fix which @@ -79,6 +86,7 @@ typedef struct mn_stats mn_stats; X(DRAGONFLY_PLUS_ROUTER, "modelnet_dragonfly_plus_router", "dragonfly_plus_router", &dragonfly_plus_router_method)\ X(DRAGONFLY_DALLY, "modelnet_dragonfly_dally", "dragonfly_dally", &dragonfly_dally_method)\ X(DRAGONFLY_DALLY_ROUTER, "modelnet_dragonfly_dally_router", "dragonfly_dally_router", &dragonfly_dally_router_method)\ + X(CONGESTION_CONTROLLER, "congestion_controller", "congestion_controller", NULL)\ X(MAX_NETS, NULL, NULL, NULL) #define X(a,b,c,d) a, diff --git a/codes/net/dragonfly-dally.h b/codes/net/dragonfly-dally.h index ed55c2ea..9f89f60b 100644 --- a/codes/net/dragonfly-dally.h +++ b/codes/net/dragonfly-dally.h @@ -22,6 +22,8 @@ struct terminal_dally_message int magic; /* flit travel start time*/ tw_stime travel_start_time; + /* flit travel end time*/ + tw_stime travel_end_time; /* packet ID of the flit */ unsigned long long packet_ID; /* event type of the flit */ @@ -37,21 +39,30 @@ struct terminal_dally_message tw_lpid sender_mn_lp; // source modelnet id /* destination terminal ID of the dragonfly */ tw_lpid dest_terminal_lpid; - int dfdally_dest_terminal_id; //this is the terminal id in the dfdally network in range [0-total_num_terminals) + unsigned int dfdally_src_terminal_id; + unsigned int dfdally_dest_terminal_id; //this is the terminal id in the dfdally network in range [0-total_num_terminals) /* source terminal ID of the dragonfly */ unsigned int src_terminal_id; /* message originating router id. MM: Can we calculate it through * sender_mn_lp??*/ unsigned int origin_router_id; + int app_id; //id of the job associated with this terminal TODO - this will cause a problem if multiple job workload LPs are mapped to one terminal + /* number of hops traversed by the packet */ short my_N_hop; short my_l_hop, my_g_hop; + short my_hops_cur_group; short saved_channel; short saved_vc; int next_stop; + //encoded time when received at a router + tw_stime this_router_arrival; + //encoded time when departed from router + tw_stime this_router_ptp_latency; + /* Intermediate LP ID from which this message is coming */ unsigned int intm_lp_id; /* last hop of the message, can be a terminal, local router or global router */ @@ -73,11 +84,13 @@ struct terminal_dally_message // For buffer message short vc_index; + short rail_id; int output_chan; model_net_event_return event_rc; int is_pull; uint32_t pull_size; int path_type; + int saved_app_id; /* for reverse computation */ short num_rngs; @@ -94,7 +107,9 @@ struct terminal_dally_message unsigned long long * rc_qos_data; int * rc_qos_status; + short saved_send_loop; tw_stime saved_available_time; + tw_stime saved_min_lat; tw_stime saved_avg_time; tw_stime saved_rcv_time; tw_stime saved_busy_time; diff --git a/codes/net/dragonfly-plus.h b/codes/net/dragonfly-plus.h index 2441516a..1c7d7485 100644 --- a/codes/net/dragonfly-plus.h +++ b/codes/net/dragonfly-plus.h @@ -46,6 +46,7 @@ struct terminal_plus_message /* number of hops traversed by the packet */ short my_N_hop; short my_l_hop, my_g_hop; + short my_hops_cur_group; short saved_channel; short saved_vc; @@ -62,7 +63,7 @@ struct terminal_plus_message //DFP Specific Routing int intm_rtr_id; //Router ID of the intermediate router for nonminimal routes - int intm_group_id; //Group ID of the intermediate router for nonminimal routes + int intm_grp_id; //Group ID of the intermediate router for nonminimal routes short dfp_upward_channel_flag; @@ -79,6 +80,7 @@ struct terminal_plus_message // For buffer message short vc_index; + short rail_id; int output_chan; model_net_event_return event_rc; int is_pull; diff --git a/codes/network-manager/dragonfly-network-manager.h b/codes/network-manager/dragonfly-network-manager.h new file mode 100644 index 00000000..a4722a58 --- /dev/null +++ b/codes/network-manager/dragonfly-network-manager.h @@ -0,0 +1,572 @@ +#ifndef DFLY_CONNECTION_MANAGER_H +#define DFLY_CONNECTION_MANAGER_H + +/** + * dragonfly-network-manager.h + * Neil McGlohon + * + * Copyright (c) 2021 Rensselaer Polytechnic Institute + */ +#include +#include +#include +#include +#include "codes/codes.h" +#include "codes/model-net.h" +#include +#include +#include + +using namespace std; + +class DragonflyConnectionManager; +class DragonflyNetworkManager; + +/** + * @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 = 2, + CONN_TERMINAL = 3, + CONN_INJECTION = 4, +}; + +enum ManagerType +{ + MAN_ROUTER = 1, + MAN_TERMINAL = 2 +}; + +/** + * @brief Struct for basic link information for loading network + */ +struct Link_Info +{ + int src_gid; + int dest_gid; + int rail_id; + double bandwidth; + ConnectionType conn_type; +}; + + +/** + * @brief Struct for complete connection information + * @note it is inadvisable to create child classes from this, unless the + * container that the child is put in is specifically templated for + * the child class, the instance will be casted to the parent and + * you'll lose fields. Yes this is dirty but safe. + */ +struct Connection +{ + int port; //port ID of the connection + 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 + double bandwidth; + int link_id; //For repeated links - starts at 0 + int is_failed; //boolean value for whether or not the link is considered failed + int rail_or_planar_id; //rail ID if coming to/from terminal, planar ID if router-router + ConnectionType conn_type; //type of the connection: CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL + + bool operator==(const Connection &other) const + { return ( port == other.port + && src_lid == other.src_lid + && src_gid == other.src_gid + && src_group_id == other.src_group_id + && dest_lid == other.dest_lid + && dest_gid == other.dest_gid + && dest_group_id == other.dest_group_id + && link_id == other.link_id + && bandwidth == other.bandwidth + && is_failed == other.is_failed + && rail_or_planar_id == other.rail_or_planar_id + && conn_type == other.conn_type); + } +}; + +template +inline void hash_combine(std::size_t& seed, const T& val) +{ + std::hash hasher; + seed ^= hasher(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +namespace std { + + template <> + struct hash + { + std::size_t operator()(const Connection& k) const + { + using std::size_t; + using std::hash; + + // Compute individual hash values for first, + // second and third and combine them using XOR + // and bit shifting: + + return ((hash()(k.port) + ^ (hash()(k.src_gid) << 1)) >> 1) + ^ (hash()(k.dest_gid) << 1) + ^ (hash()(k.rail_or_planar_id) << 1); + } + }; + + template<> + struct hash > + { + std::size_t operator()(const pair& k) const + { + using std::size_t; + using std::hash; + + size_t seed = 0; + hash_combine(seed, k.first); + hash_combine(seed, k.second); + return seed; + } + }; + + template<> + struct hash > + { + std::size_t operator()(const tuple& k) const + { + using std::size_t; + using std::hash; + + size_t seed = 0; + hash_combine(seed, get<0>(k)); + hash_combine(seed, get<1>(k)); + hash_combine(seed, get<2>(k)); + hash_combine(seed, get<3>(k)); + return seed; + } + }; + +}; + +inline bool operator<(const Connection& lhs, const Connection& rhs) +{ + return lhs.port < rhs.port; +} + +/** + * @class NetworkManager + * + * @brief + * This class is meant to organize the connections that form the network as a whole + * and also stores all connection managers. + * + * @note + * This class was designed with dragonfly type topologies in mind (local groups of routers) + * Certain parts may not make sense for other topologies, they might work fine, but no guarantees. + */ +class DragonflyNetworkManager { + int _total_routers; + int _total_terminals; + int _total_groups; + int _num_rails; + int _total_planes; + int _num_routers_per_group; + int _num_groups_per_plane; + int _num_lc_pr; //num local conns per router + int _num_gc_pr; //num global conns per router + int _num_cn_pr; //num cn conns per router + int _num_unique_term_pr; //num unique terminals per router + + int _max_local_hops_per_group; + int _max_global_hops; + + + int _num_router_conns; //total number of router-router links + int _num_router_terminal_conns; //total number of terminal links + int _num_terminal_router_conns; + bool _link_failures_enabled; + int _num_failed_router_conns; + int _num_failed_router_terminal_conns; + + // Connection* self_conn_ptr; + + map< int, vector > _router_link_failure_lists; //maps router ID to a vector of Link Infos that contain dest router GIDs that it has a FAILED connection to, one item for each failed connection + map< int, vector > _router_terminal_link_failure_lists; //maps router ID to a vector of Link Infos that contain dest terminal GIDs that it has a FAILED connection to, one item for each failed connection + + //storage maps - these are the 'owners' of the connections contained. + unordered_map< int, vector< Connection* > > _router_connections_map; //maps router ID to a vector of all router-router connections that that router has + unordered_map< int, vector< Connection* > > _router_terminal_connections_map; //maps router ID to a vector of all terminal connections that that router has + unordered_map< int, vector< Connection* > > _terminal_router_connections_map; + + //useful maps - helpful ways of organizing the connection pointers stored above + unordered_map< int, vector > _router_to_router_global_conn_map; + unordered_map< int, vector > _router_to_router_local_conn_map; + unordered_map< pair, vector< Connection* > > _router_to_router_connection_map; //maps pair(src_gid, dest_gid) to a vector of connection pointers that go from src gid to dest gid + unordered_map< pair, vector< Connection* > > _router_to_terminal_connection_map; //maps pair(src_gid, dest_term_gid) to a vector of connection pointers taht go from src gid router to dest_term id + unordered_map< pair, vector< Connection* > > _terminal_to_router_connection_map; + unordered_map< pair, vector< Connection* > > _router_to_group_connection_map; //maps pair(src_gid, dest_group_id) to a vector of connections that go from src_gid to any router in the dest group + map< pair, vector< Connection* > > _global_group_connection_map; //maps pair(src group id, dest group id) to a vector of connection pointers that match that pattern + + set _router_ids_with_terminals; + unordered_map< tuple, set > _valid_next_conn_map; + + int*** adjacency_matrix; //total_routers x total_routers in size, 1 for if any connection exists 0 for if no connection exists + int*** adjacency_matrix_nofail; + + int** _shortest_path_vals; + int** _next; + unordered_map, vector > _shortest_path_nexts; + + vector< DragonflyConnectionManager > _connection_manager_list; //list of all connection managers in the network + vector< DragonflyConnectionManager > _terminal_connection_manager_list; // list of all connection mangers for TERMINALS in the network + + bool _is_solidified; + +public: + DragonflyNetworkManager(); + + DragonflyNetworkManager(int total_routers, int total_terminals, int num_routers_per_group, int num_lc_per_router, int num_gc_per_router, int num_cn_conns_per_router, int num_rails, int num_planes, int max_local_hops, int max_global_hops); + + void enable_link_failures(); + + bool is_link_failures_enabled(); + + DragonflyConnectionManager& get_connection_manager_for_router(int router_gid); + + DragonflyConnectionManager& get_connection_manager_for_terminal(int terminal_gid); + + void add_link(Link_Info link); + + vector get_attached_router_ids_from_terminal(int terminal_gid); + + vector get_attached_terminal_ids_from_router(int router_gid); + + void add_link_failure_info(Link_Info failed_link); + + void fail_connection(Link_Info failed_link); + + int get_failed_count_from_vector(vector conns); + + void calculate_floyd_warshall_shortest_paths(); + + int get_shortest_dist_between_routers(int src_gid, int dest_gid); + + vector get_shortest_nexts(int src_gid, int dest_gid); + + set get_valid_next_hops_conns(int src_gid, int dest_gid, int max_local, int exact_global); + + int get_max_local_hops(); + + int get_max_global_hops(); + + void add_conns_to_connection_managers(); + + void solidify_network(); +}; + +/** + * @class DragonflyConnectionManager + * + * @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. + * + * @note + * This class assumes that each router group has the same number of routers in it: _num_routers_per_group. + */ +class DragonflyConnectionManager { +public: + ManagerType _manType; //whether this is a router or a terminal connection manager + map< int, Connection > _portMap; //Mapper for ports to connection references - includes failed connections + + // includes failed connections + 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 > > intraGroupConnectionsGID; //direct connections within a group - IDs are global IDs + 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 + map< int, vector< Connection > > injectionConnections; //this is specific for terminal origins, maps a router ID to connections to it + + map< int, vector< Connection > > _connections_to_groups_map; //maps group ID to connections to said group + vector< int > _other_groups_i_connect_to; + map< int, vector< Connection > > _all_conns_by_type_map; + map< int, vector< Connection > > _routed_connections_to_group_map; //maps group ID to connections within local group that go to specified group + map< int, vector< Connection > > _next_hop_routed_connections_to_group_map; //maps group ID to connections within local group that directly lead to a router that goes to the specified group + map< int, vector > _routed_router_gids_to_group_map; //maps group ID to a vector of Router GIDs within current group that have a connection to the group ID + map< int, vector > _group_group_connection_map; + + // doesn't include failed connections - these are copies with the failed links removed for optimized getter performance + map< int, vector< Connection > > intraGroupConnections_nofail; + map< int, vector< Connection > > intraGroupConnectionsGID_nofail; + map< int, vector< Connection > > globalConnections_nofail; + map< int, vector< Connection > > terminalConnections_nofail; + map< int, vector< Connection > > injectionConnections_nofail; + + map< int, vector< Connection > > _connections_to_groups_map_nofail; + vector< int > _other_groups_i_connect_to_nofail; + vector< int > _accessible_group_ids_nofail; //group IDs that this router can reach directly or with one intermediate router hop within its local group + map< int, vector< Connection > > _all_conns_by_type_map_nofail; + map< int, vector< Connection > > _routed_connections_to_group_map_nofail; //maps group ID to connections within local group that go to specified group + map< int, vector< Connection > > _next_hop_routed_connections_to_group_map_nofail; //maps group ID to connections within local group that directly lead to a router that goes to the specified group + map< int, vector > _routed_router_gids_to_group_map_nofail; //maps group ID to a vector of Router GIDs within current group that have a connection to the group ID + map< int, vector > _group_group_connection_map_nofail; + + + set _connected_to_terminal_gids; + set _connected_to_router_gids; + + // other information + 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 _used_injection_ports; //number of used ports for packet injection into the network + + int _failed_intra_ports; //number of failed ports for intra connections + int _failed_inter_ports; //number of failed ports for inter connections + int _failed_terminal_ports; //number of failed ports for terminal connections + int _failed_injection_ports; //number of failed ports for packet injection into the network + + 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 _max_injection_ports; //maximum number of ports for packet injection into the network + + int _num_routers_per_group; //number of routers per group - used for turning global ID into local and back + int _num_groups; + int _source_plane; + + bool is_solidified; //flag for whether or not solidification has taken place so that this can be checked at the end of router init + +public: + DragonflyConnectionManager(); + DragonflyConnectionManager(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, int num_groups); + DragonflyConnectionManager(int src_id_local, int src_id_global, int src_group, int max_intra, int max_inter, int max_term, int max_injection, int num_router_per_group, int num_groups, int num_planes, ManagerType manType); + /** + * @brief Adds a connection to the manager, returns a reference to it + * @param dest_gid the global ID of the destination router + * @param type the type of the connection, CONN_LOCAL, CONN_GLOBAL, or CONN_TERMINAL + * @return returns the port number that it was added to + + */ + int add_connection(int dest_gid, ConnectionType type); + + /** + * @brief Adds a reference to a connection to the manager + * @param conn connection to a connection created by the NetworkManager + * @return returns the port number that it was added to + */ + int add_connection(Connection conn); + + void add_group_group_connection_information(map, vector > group_group_connections); + + void set_routed_connections_to_groups(map > conn_map); + + vector< Connection > get_routed_connections_to_group(int group_id, bool force_next_hop, bool include_failed); + + vector< Connection > get_routed_connections_to_group(int group_id, bool force_next_hop); + + vector< Connection > get_next_hop_routed_connections_to_group(int group_id, bool include_failed); + + vector< Connection > get_next_hop_routed_connections_to_group(int group_id); + + vector< int > get_accessible_group_ids(); + + vector< int > get_router_gids_with_global_to_group(int group_id); + + vector< int > get_router_gids_with_global_to_group(int group_id, bool include_failed); + + vector< int > get_groups_that_connect_to_group(int dest_group, bool include_failed); + + vector< int > get_groups_that_connect_to_group(int dest_group); + + vector< int > get_connected_gids_by_connection_type(ConnectionType conn_type); + + /** + * @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 + * @param include_failed whether or not to include failed links in query + */ + vector get_ports(int dest_id, ConnectionType type, bool include_failed); + + /** + * @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 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, bool include_failed); + + /** + * @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 + * @param include_failed boolean whether or not to include failed links as possible connections + * @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, bool include_failed); + + /** + * @brief returns true if a connection exists in the manager from the source to the specified destination ID BY TYPE - will not return true if only existing links are failed + * @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 + * @param include_failed whether or not to include failed links in query + * @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, bool include_failed); + + /** + * @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 + * @param account_for_failed do we adjust the count due to failed links? + */ + int get_total_used_ports(bool account_for_failed); + + /** + * @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 + * @param account_for_failed do we adjust the count due to failed links? + */ + int get_used_ports_for(ConnectionType type, bool account_for_failed); + + /** + * @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); + + /** + * @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); + + /** + * @brief returns the boolean status of whether or not the specified port has failed + * @param port_num the number of the port in question + */ + bool get_port_failed_status(int port_num); + + /** + * @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 + */ + vector< Connection > get_connections_to_gid(int dest_id, ConnectionType type, bool include_failed); + + /** + * @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 + */ + vector< Connection > get_connections_to_gid(int dest_id, ConnectionType type); + + /** + * @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 + * @param include_failed whether or not to include failed links in query + */ + vector< Connection > get_connections_to_group(int dest_group_id, bool include_failed); + + /** + * @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); + + /** + * @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 + * @param include_failed whether or not to include failed links in query + * @note this will return connections to same destination on different ports as individual connections + */ + vector< Connection > get_connections_by_type(ConnectionType type, bool include_failed); + + /** + * @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); + + /** + * @brief returns a vector of all group IDs that the router has a global connection to + * @param include_failed whether or not to include failed links in query + * @note this does not include the router's own group as that is a given + */ + vector< int > get_connected_group_ids(bool include_failed); + + /** + * @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(); + + /** + * @brief function to populate various optimized data structures with various connections + * @note must be executed before simulation start + */ + void solidify_connections(); + + /** + * @brief returns true if manager has been solidified - should be run in router init + */ + bool check_is_solidified(); + /** + * @brief prints out the state of the connection manager + */ + void print_connections(); +}; + +#endif /* end of include guard:*/ \ No newline at end of file diff --git a/codes_config.h.in b/codes_config.h.in new file mode 100644 index 00000000..82554a42 --- /dev/null +++ b/codes_config.h.in @@ -0,0 +1,18 @@ + + + +// ross + +// dumpi + +// swm +#define SWM_DATAROOTDIR "${SWM_DATAROOTDIR}" + + +// damaris + + +// darshan + + +// cortex \ No newline at end of file diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 00000000..a6d21ae5 --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,8394 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 2014 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program or library that is built +# using GNU Libtool, you may include this file under the same +# distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +]) + +# serial 58 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS=$ltmain + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_PREPARE_CC_BASENAME +# ----------------------- +m4_defun([_LT_PREPARE_CC_BASENAME], [ +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +func_cc_basename () +{ + for cc_temp in @S|@*""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac + done + func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +} +])# _LT_PREPARE_CC_BASENAME + + +# _LT_CC_BASENAME(CC) +# ------------------- +# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME, +# but that macro is also expanded into generated libtool script, which +# arranges for $SED and $ECHO to be set by different means. +m4_defun([_LT_CC_BASENAME], +[m4_require([_LT_PREPARE_CC_BASENAME])dnl +AC_REQUIRE([_LT_DECL_SED])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl +func_cc_basename $1 +cc_basename=$func_cc_basename_result +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl +m4_require([_LT_CMD_TRUNCATE])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options that allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a '.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld=$lt_cv_prog_gnu_ld + +old_CC=$CC +old_CFLAGS=$CFLAGS + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from 'configure', and 'config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# 'config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain=$ac_aux_dir/ltmain.sh +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the 'libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to 'config.status' so that its +# declaration there will have the same value as in 'configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags='_LT_TAGS'dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into 'config.status', and then the shell code to quote escape them in +# for loops in 'config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# '#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test 0 = "$lt_write_fail" && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +'$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test 0 != $[#] +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try '$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try '$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test yes = "$silent" && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options that allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}"; then + setopt NO_GLOB_SUBST + fi + + cfgfile=${ofile}T + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL +# Generated automatically by $as_me ($PACKAGE) $VERSION +# NOTE: Changes made to this file will be lost: look at ltmain.sh. + +# Provide generalized library-building support services. +# Written by Gordon Matzigkeit, 1996 + +_LT_COPYING +_LT_LIBTOOL_TAGS + +# Configured defaults for sys_lib_dlsearch_path munging. +: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"} + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + cat <<'_LT_EOF' >> "$cfgfile" + +# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE + +_LT_PREPARE_MUNGE_PATH_LIST +_LT_PREPARE_CC_BASENAME + +# ### END FUNCTIONS SHARED WITH CONFIGURE + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test set != "${COLLECT_NAMES+set}"; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "$LT_MULTI_MODULE"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test 0 = "$_lt_result"; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS=$save_LDFLAGS + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + 10.[[012]][[,.]]*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test yes = "$lt_cv_apple_cc_single_mod"; then + _lt_dar_single_mod='$single_module' + fi + if test yes = "$lt_cv_ld_exported_symbols_list"; then + _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib' + fi + if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test yes = "$lt_cv_ld_force_load"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined + case $cc_basename in + ifort*|nagfor*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test yes = "$_lt_dar_can_shared"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil" + m4_if([$1], [CXX], +[ if test yes != "$lt_cv_apple_cc_single_mod"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test set = "${lt_cv_aix_libpath+set}"; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script that will find a shell with a builtin +# printf (that we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case $ECHO in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@], + [Search for dependent libraries within DIR (or the compiler's sysroot + if not specified).])], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case $with_sysroot in #( + yes) + if test yes = "$GCC"; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([$with_sysroot]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and where our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test no = "$enable_libtool_lock" || enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out what ABI is being produced by ac_compile, and set mode + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE=32 + ;; + *ELF-64*) + HPUX_IA64_MODE=64 + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test yes = "$lt_cv_prog_gnu_ld"; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +mips64*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + emul=elf + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + emul="${emul}32" + ;; + *64-bit*) + emul="${emul}64" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *MSB*) + emul="${emul}btsmip" + ;; + *LSB*) + emul="${emul}ltsmip" + ;; + esac + case `/usr/bin/file conftest.$ac_objext` in + *N32*) + emul="${emul}n32" + ;; + esac + LD="${LD-ld} -m $emul" + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. Note that the listed cases only cover the + # situations where additional linker options are needed (such as when + # doing 32-bit compilation for a host where ld defaults to 64-bit, or + # vice versa); the common cases where no linker options are needed do + # not appear in the list. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test yes != "$lt_cv_cc_needs_belf"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS=$SAVE_CFLAGS + fi + ;; +*-*solaris*) + # Find out what ABI is being produced by ac_compile, and set linker + # options accordingly. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*|x86_64-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD=${LD-ld}_sol2 + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks=$enable_libtool_lock +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cr} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test 0 -eq "$ac_status"; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test 0 -ne "$ac_status"; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test no = "$lt_cv_ar_at_file"; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + bitrig* | openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test yes = "[$]$2"; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS=$save_LDFLAGS +]) + +if test yes = "[$]$2"; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring=ABCD + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len" && \ + test undefined != "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test X`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test 17 != "$i" # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n "$lt_cv_sys_max_cmd_len"; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes = "$cross_compiling"; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisibility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test yes != "$enable_dlopen"; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen=load_add_on + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen=LoadLibrary + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[ + lt_cv_dlopen=dyld + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + tpf*) + # Don't try to run any link tests for TPF. We know it's impossible + # because TPF is a cross-compiler, and we know how we open DSOs. + lt_cv_dlopen=dlopen + lt_cv_dlopen_libs= + lt_cv_dlopen_self=no + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen=shl_load], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen=dlopen], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test no = "$lt_cv_dlopen"; then + enable_dlopen=no + else + enable_dlopen=yes + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS=$CPPFLAGS + test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS=$LDFLAGS + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS=$LIBS + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test yes = "$lt_cv_dlopen_self"; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS=$save_CPPFLAGS + LDFLAGS=$save_LDFLAGS + LIBS=$save_LIBS + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links=nottested +if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test no = "$hard_links"; then + AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/", + [Define to the sub-directory where libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then + + # We can hardcode non-existent directories. + if test no != "$_LT_TAGVAR(hardcode_direct, $1)" && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" && + test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test relink = "$_LT_TAGVAR(hardcode_action, $1)" || + test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then + # Fast installation is not supported + enable_fast_install=no +elif test yes = "$shlibpath_overrides_runpath" || + test no = "$enable_shared"; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP"; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_PREPARE_MUNGE_PATH_LIST +# --------------------------- +# Make sure func_munge_path_list() is defined correctly. +m4_defun([_LT_PREPARE_MUNGE_PATH_LIST], +[[# func_munge_path_list VARIABLE PATH +# ----------------------------------- +# VARIABLE is name of variable containing _space_ separated list of +# directories to be munged by the contents of PATH, which is string +# having a format: +# "DIR[:DIR]:" +# string "DIR[ DIR]" will be prepended to VARIABLE +# ":DIR[:DIR]" +# string "DIR[ DIR]" will be appended to VARIABLE +# "DIRP[:DIRP]::[DIRA:]DIRA" +# string "DIRP[ DIRP]" will be prepended to VARIABLE and string +# "DIRA[ DIRA]" will be appended to VARIABLE +# "DIR[:DIR]" +# VARIABLE will be replaced by "DIR[ DIR]" +func_munge_path_list () +{ + case x@S|@2 in + x) + ;; + *:) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\" + ;; + x:*) + eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + *::*) + eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\" + eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\" + ;; + *) + eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\" + ;; + esac +} +]])# _LT_PREPARE_PATH_LIST + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test yes = "$GCC"; then + case $host_os in + darwin*) lt_awk_arg='/^libraries:/,/LR/' ;; + *) lt_awk_arg='/^libraries:/' ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;; + *) lt_sed_strip_eq='s|=/|/|g' ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary... + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + # ...but if some path component already ends with the multilib dir we assume + # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer). + case "$lt_multi_os_dir; $lt_search_path_spec " in + "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*) + lt_multi_os_dir= + ;; + esac + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir" + elif test -n "$lt_multi_os_dir"; then + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS = " "; FS = "/|\n";} { + lt_foo = ""; + lt_count = 0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo = "/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=.so +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +AC_ARG_VAR([LT_SYS_LIBRARY_PATH], +[User-defined run-time library search path.]) + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='$libname$release$shared_ext$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test ia64 = "$host_cpu"; then + # AIX 5 supports IA64 + library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line '#! .'. This would cause the generated library to + # depend on '.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # Using Import Files as archive members, it is possible to support + # filename-based versioning of shared library archives on AIX. While + # this would work for both with and without runtime linking, it will + # prevent static linking of such archives. So we do filename-based + # shared library versioning with .so extension only, which is used + # when both runtime linking and shared linking is enabled. + # Unfortunately, runtime linking may impact performance, so we do + # not want this to be the default eventually. Also, we use the + # versioned .so libs for executables only if there is the -brtl + # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only. + # To allow for filename-based versioning support, we need to create + # libNAME.so.V as an archive file, containing: + # *) an Import File, referring to the versioned filename of the + # archive as well as the shared archive member, telling the + # bitwidth (32 or 64) of that shared object, and providing the + # list of exported symbols of that shared object, eventually + # decorated with the 'weak' keyword + # *) the shared object with the F_LOADONLY flag set, to really avoid + # it being seen by the linker. + # At run time we better use the real file rather than another symlink, + # but for link time we create the symlink libNAME.so -> libNAME.so.V + + case $with_aix_soname,$aix_use_runtimelinking in + # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + aix,yes) # traditional libtool + dynamic_linker='AIX unversionable lib.so' + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + aix,no) # traditional AIX only + dynamic_linker='AIX lib.a[(]lib.so.V[)]' + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + ;; + svr4,*) # full svr4 only + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,yes) # both, prefer svr4 + dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]" + library_names_spec='$libname$release$shared_ext$major $libname$shared_ext' + # unpreferred sharedlib libNAME.a needs extra handling + postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"' + postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"' + # We do not specify a path in Import Files, so LIBPATH fires. + shlibpath_overrides_runpath=yes + ;; + *,no) # both, prefer aix + dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]" + library_names_spec='$libname$release.a $libname.a' + soname_spec='$libname$release$shared_ext$major' + # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling + postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)' + postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"' + ;; + esac + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='$libname$shared_ext' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext' + library_names_spec='$libname.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec=$LIB + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$major$shared_ext $libname$shared_ext' + soname_spec='$libname$release$major$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=no + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + if test 32 = "$HPUX_IA64_MODE"; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + sys_lib_dlsearch_path_spec=/usr/lib/hpux32 + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + sys_lib_dlsearch_path_spec=/usr/lib/hpux64 + fi + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test yes = "$lt_cv_prog_gnu_ld"; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff" + sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +linux*android*) + version_type=none # Android doesn't support versioned libraries. + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext' + soname_spec='$libname$release$shared_ext' + finish_cmds= + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + dynamic_linker='Android linker' + # Don't embed -rpath directories since the linker doesn't support them. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Ideally, we could use ldconfig to report *all* directores which are + # searched for libraries, however this is still not possible. Aside from not + # being certain /sbin/ldconfig is available, command + # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64, + # even though it is searched at run-time. Try to do the best guess by + # appending ld.so.conf contents (and includes) to the search path. + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd* | bitrig*) + version_type=sunos + sys_lib_dlsearch_path_spec=/usr/lib + need_lib_prefix=no + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + need_version=no + else + need_version=yes + fi + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +os2*) + libname_spec='$name' + version_type=windows + shrext_cmds=.dll + need_version=no + need_lib_prefix=no + # OS/2 can only load a DLL with a base name of 8 characters or less. + soname_spec='`test -n "$os2dllname" && libname="$os2dllname"; + v=$($ECHO $release$versuffix | tr -d .-); + n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _); + $ECHO $n$v`$shared_ext' + library_names_spec='${libname}_dll.$libext' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=BEGINLIBPATH + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + postinstall_cmds='base_file=`basename \$file`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='$libname$release$shared_ext$major' + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test yes = "$with_gnu_ld"; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec; then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext' + soname_spec='$libname$shared_ext.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=sco + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test yes = "$with_gnu_ld"; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test no = "$dynamic_linker" && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test yes = "$GCC"; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then + sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec +fi + +if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then + sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec +fi + +# remember unaugmented sys_lib_dlsearch_path content for libtool script decls... +configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec + +# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code +func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH" + +# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool +configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2], + [Detected run-time system search path for libraries]) +_LT_DECL([], [configure_time_lt_sys_library_path], [2], + [Explicit LT_SYS_LIBRARY_PATH set during ./configure time]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program that can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD=$MAGIC_CMD + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$1"; then + lt_cv_path_MAGIC_CMD=$ac_dir/"$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD=$lt_cv_path_MAGIC_CMD + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS=$lt_save_ifs + MAGIC_CMD=$lt_save_MAGIC_CMD + ;; +esac]) +MAGIC_CMD=$lt_cv_path_MAGIC_CMD +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program that can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test no = "$withval" || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test yes = "$GCC"; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return, which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD=$ac_prog + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test yes = "$with_gnu_ld"; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD=$ac_dir/$ac_prog + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i +cat conftest.i conftest.i >conftest2.i +: ${lt_DD:=$DD} +AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd], +[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=: +fi]) +rm -f conftest.i conftest2.i conftest.out]) +])# _LT_PATH_DD + + +# _LT_CMD_TRUNCATE +# ---------------- +# find command to truncate a binary pipe +m4_defun([_LT_CMD_TRUNCATE], +[m4_require([_LT_PATH_DD]) +AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin], +[printf 0123456789abcdef0123456789abcdef >conftest.i +cat conftest.i conftest.i >conftest2.i +lt_cv_truncate_bin= +if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then + cmp -s conftest.i conftest.out \ + && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1" +fi +rm -f conftest.i conftest2.i conftest.out +test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"]) +_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1], + [Command to truncate a binary pipe]) +])# _LT_CMD_TRUNCATE + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# 'unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# that responds to the $file_magic_cmd with a given extended regex. +# If you have 'file' or equivalent on your system and you're not sure +# whether 'pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[[4-9]]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[[45]]*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + if ( file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd* | bitrig*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +os2*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM=$NM +else + lt_nm_to_check=${ac_tool_prefix}nm + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS=$lt_save_ifs + test -z "$ac_dir" && ac_dir=. + tmp_nm=$ac_dir/$lt_tmp_nm + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the 'sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty + case $build_os in + mingw*) lt_bad_file=conftest.nm/nofile ;; + *) lt_bad_file=/dev/null ;; + esac + case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in + *$lt_bad_file* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break 2 + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break 2 + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS=$lt_save_ifs + done + : ${lt_cv_path_NM=no} +fi]) +if test no != "$lt_cv_path_NM"; then + NM=$lt_cv_path_NM +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols -headers" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test : != "$DUMPBIN"; then + NM=$DUMPBIN + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh; + # decide which one to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd=$ECHO + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test yes != "$lt_cv_path_mainfest_tool"; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# _LT_DLL_DEF_P([FILE]) +# --------------------- +# True iff FILE is a Windows DLL '.def' file. +# Keep in sync with func_dll_def_p in the libtool script +AC_DEFUN([_LT_DLL_DEF_P], +[dnl + test DEF = "`$SED -n dnl + -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace + -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments + -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl + -e q dnl Only consider the first "real" line + $1`" dnl +])# _LT_DLL_DEF_P + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw) + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM=-lm) + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test yes = "$GCC"; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test ia64 = "$host_cpu"; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Gets list of data symbols to import. + lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'" + # Adjust the below global symbol transforms to fixup imported variables. + lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'" + lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'" + lt_c_name_lib_hook="\ + -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\ + -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'" +else + # Disable hooks by default. + lt_cv_sys_global_symbol_to_import= + lt_cdecl_hook= + lt_c_name_hook= + lt_c_name_lib_hook= +fi + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n"\ +$lt_cdecl_hook\ +" -e 's/^T .* \(.*\)$/extern int \1();/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n"\ +$lt_c_name_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'" + +# Transform an extracted symbol line into symbol name with lib prefix and +# symbol address. +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\ +$lt_c_name_lib_hook\ +" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\ +" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\ +" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function, + # D for any global variable and I for any imported variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\ +" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\ +" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\ +" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\ +" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD + if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE +/* DATA imports from DLLs on WIN32 can't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined __osf__ +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS=conftstm.$ac_objext + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test yes = "$pipe_works"; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1], + [Transform the output of nm into a list of symbols to manually relocate]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([nm_interface], [lt_cv_nm_interface], [1], + [The name lister interface]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64, which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test yes = "$GCC"; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the '-m68020' flag to GCC prevents building anything better, + # like '-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test ia64 = "$host_cpu"; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + case $cc_basename in + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + case $host_os in + os2*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static' + ;; + esac + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + # old Intel for x86_64, which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # flang / f18. f95 an alias for gfortran or flang on Debian + flang* | f18* | f95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms that do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ' (' and ')$', so one must not match beginning or + # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc', + # as well as any symbol that contains 'd'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test yes != "$GCC"; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd* | bitrig*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test yes = "$with_gnu_ld"; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test yes = "$lt_use_gnu_ld_interface"; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='$wl' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test ia64 != "$host_cpu"; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test linux-dietlibc = "$host_os"; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test no = "$tmp_diet" + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + nagfor*) # NAGFOR 5.3 + tmp_sharedflag='-Wl,-shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + tcc*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic' + ;; + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to GNU nm, but means don't demangle to AIX nm. + # Without the "-l" option, or with the "-B" option, AIX nm treats + # weak defined symbols like other global defined symbols, whereas + # GNU nm marks them as "W". + # While the 'weak' keyword is ignored in the Export File, we need + # it in the Import File for the 'aix-soname' feature, so we have + # to replace the "-B" option with "-P" for AIX nm. + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then + aix_use_runtimelinking=yes + break + fi + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # traditional, no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GCC"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag="$shared_flag "'$wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + + hpux10*) + if test yes,no = "$GCC,$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test yes,no = "$GCC,$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS=$LDFLAGS + LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS=$save_LDFLAGS]) + if test yes = "$lt_cv_irix_exported_symbol"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + linux*) + case $cc_basename in + tcc*) + # Fabrice Bellard et al's Tiny C Compiler + _LT_TAGVAR(ld_shlibs, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + osf3*) + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test yes = "$GCC"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test yes = "$GCC"; then + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='$wl' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. GCC discards it without '$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test yes = "$GCC"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test sequent = "$host_vendor"; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + if test yes = "$GCC"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test sni = "$host_vendor"; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test yes,yes = "$GCC,$enable_shared"; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting $shlibpath_var if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC=$CC +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report what library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC=$lt_save_CC +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test no != "$CXX" && + ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) || + (test g++ != "$CXX"))); then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_caught_CXX_error"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test yes = "$GXX"; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test yes = "$GXX"; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test yes = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='$wl' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test ia64 = "$host_cpu"; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag= + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # have runtime linking enabled, and use it for executables. + # For shared libraries, we enable/disable runtime linking + # depending on the kind of the shared library created - + # when "with_aix_soname,aix_use_runtimelinking" is: + # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables + # "aix,yes" lib.so shared, rtl:yes, for executables + # lib.a static archive + # "both,no" lib.so.V(shr.o) shared, rtl:yes + # lib.a(lib.so.V) shared, rtl:no, for executables + # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a(lib.so.V) shared, rtl:no + # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables + # lib.a static archive + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then + # With aix-soname=svr4, we create the lib.so.V shared archives only, + # so we don't have lib.a shared libs to link our executables. + # We have to force runtime linking in this case. + aix_use_runtimelinking=yes + LDFLAGS="$LDFLAGS -Wl,-brtl" + fi + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='$wl-f,' + case $with_aix_soname,$aix_use_runtimelinking in + aix,*) ;; # no import file + svr4,* | *,yes) # use import file + # The Import File defines what to hardcode. + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + ;; + esac + + if test yes = "$GXX"; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`$CC -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test yes = "$aix_use_runtimelinking"; then + shared_flag=$shared_flag' $wl-G' + fi + # Need to ensure runtime linking is disabled for the traditional + # shared library, or the linker may eventually find shared libraries + # /with/ Import File - we do not want to mix them. + shared_flag_aix='-shared' + shared_flag_svr4='-shared $wl-G' + else + # not using gcc + if test ia64 = "$host_cpu"; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test yes = "$aix_use_runtimelinking"; then + shared_flag='$wl-G' + else + shared_flag='$wl-bM:SRE' + fi + shared_flag_aix='$wl-bM:SRE' + shared_flag_svr4='$wl-G' + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + # The "-G" linker flag allows undefined symbols. + _LT_TAGVAR(no_undefined_flag, $1)='-bernotok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag + else + if test ia64 = "$host_cpu"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok' + if test yes = "$with_gnu_ld"; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d' + # -brtl affects multiple linker settings, -berok does not and is overridden later + compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`' + if test svr4 != "$with_aix_soname"; then + # This is similar to how AIX traditionally builds its shared + # libraries. Need -bnortl late, we may have -brtl in LDFLAGS. + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname' + fi + if test aix != "$with_aix_soname"; then + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp' + else + # used by -dlpreopen to get the symbols + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir' + fi + _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=.dll + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp "$export_symbols" "$output_objdir/$soname.def"; + echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp"; + else + $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile=$lt_outputfile.exe + lt_tool_outputfile=$lt_tool_outputfile.exe + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file, use it as + # is; otherwise, prepend EXPORTS... + _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + shrext_cmds=.dll + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~ + $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~ + $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~ + $ECHO EXPORTS >> $output_objdir/$libname.def~ + prefix_cmds="$SED"~ + if test EXPORTS = "`$SED 1q $export_symbols`"; then + prefix_cmds="$prefix_cmds -e 1d"; + fi~ + prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~ + cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~ + $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~ + emximp -o $lib $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test yes = "$GXX"; then + if test no = "$with_gnu_ld"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib' + if test yes = "$supports_anon_versioning"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd* | bitrig*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands '-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test yes,no = "$GXX,$with_gnu_ld"; then + _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + else + # g++ 2.7 appears to require '-G' NOT '-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We CANNOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no + + _LT_TAGVAR(GCC, $1)=$GXX + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test yes != "$_lt_caught_CXX_error" + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case @S|@2 in + .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;; + *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case $prev$p in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test x-L = "$p" || + test x-R = "$p"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test no = "$pre_test_object_deps_done"; then + case $prev in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)=$prev$p + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test no = "$pre_test_object_deps_done"; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)=$p + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)=$p + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test no = "$F77"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_F77"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$G77 + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_F77" + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test no = "$FC"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test yes != "$_lt_disable_FC"; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test no = "$can_build_shared" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test yes = "$enable_shared" && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test ia64 != "$host_cpu"; then + case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in + yes,aix,yes) ;; # shared object as lib.so file only + yes,svr4,*) ;; # shared object as lib.so archive member only + yes,*) enable_static=no ;; # shared object in lib.a archive as well + esac + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test yes = "$enable_shared" || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu + _LT_TAGVAR(LD, $1)=$LD + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test yes != "$_lt_disable_FC" + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)=$LD +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to 'libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code=$lt_simple_compile_test_code + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f "$lt_ac_sed" && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test 10 -lt "$lt_ac_count" && break + lt_ac_count=`expr $lt_ac_count + 1` + if test "$lt_ac_count" -gt "$lt_ac_max"; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine what file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 00000000..94b08297 --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,437 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 8 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option '$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl 'shared' nor 'disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4], + [_LT_WITH_AIX_SONAME([aix])]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the 'shared' and +# 'disable-shared' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the 'static' and +# 'disable-static' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the 'fast-install' +# and 'disable-fast-install' LT_INIT options. +# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for pkg in $enableval; do + IFS=$lt_save_ifs + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the 'disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_AIX_SONAME([DEFAULT]) +# ---------------------------------- +# implement the --with-aix-soname flag, and support the `aix-soname=aix' +# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT +# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'. +m4_define([_LT_WITH_AIX_SONAME], +[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl +shared_archive_member_spec= +case $host,$enable_shared in +power*-*-aix[[5-9]]*,yes) + AC_MSG_CHECKING([which variant of shared library versioning to provide]) + AC_ARG_WITH([aix-soname], + [AS_HELP_STRING([--with-aix-soname=aix|svr4|both], + [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])], + [case $withval in + aix|svr4|both) + ;; + *) + AC_MSG_ERROR([Unknown argument to --with-aix-soname]) + ;; + esac + lt_cv_with_aix_soname=$with_aix_soname], + [AC_CACHE_VAL([lt_cv_with_aix_soname], + [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT) + with_aix_soname=$lt_cv_with_aix_soname]) + AC_MSG_RESULT([$with_aix_soname]) + if test aix != "$with_aix_soname"; then + # For the AIX way of multilib, we name the shared archive member + # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o', + # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File. + # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag, + # the AIX toolchain works better with OBJECT_MODE set (default 32). + if test 64 = "${OBJECT_MODE-32}"; then + shared_archive_member_spec=shr_64 + else + shared_archive_member_spec=shr + fi + fi + ;; +*) + with_aix_soname=aix + ;; +esac + +_LT_DECL([], [shared_archive_member_spec], [0], + [Shared archive member basename, for filename based shared library versioning on AIX])dnl +])# _LT_WITH_AIX_SONAME + +LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])]) +LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])]) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the 'pic-only' and 'no-pic' +# LT_INIT options. +# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR, + for lt_pkg in $withval; do + IFS=$lt_save_ifs + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS=$lt_save_ifs + ;; + esac], + [pic_mode=m4_default([$1], [default])]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the 'pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 new file mode 100644 index 00000000..48bc9344 --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,124 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software +# Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59, which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 new file mode 100644 index 00000000..fa04b52a --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 4179 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.6]) +m4_define([LT_PACKAGE_REVISION], [2.4.6]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.6' +macro_revision='2.4.6' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 00000000..c6b26f88 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,99 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software +# Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN), +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/scripts/congestion-control/ex_congestion_pattern.txt b/scripts/congestion-control/ex_congestion_pattern.txt new file mode 100644 index 00000000..3d376430 --- /dev/null +++ b/scripts/congestion-control/ex_congestion_pattern.txt @@ -0,0 +1,16 @@ +00111 +01011 +01101 +01110 +01111 +10011 +10101 +10110 +10111 +11001 +11010 +11011 +11100 +11101 +11110 +11111 diff --git a/scripts/congestion-control/ex_decongestion_pattern.txt b/scripts/congestion-control/ex_decongestion_pattern.txt new file mode 100644 index 00000000..47abd196 --- /dev/null +++ b/scripts/congestion-control/ex_decongestion_pattern.txt @@ -0,0 +1,4 @@ +00000 +01000 +10000 +11000 diff --git a/scripts/congestion-control/gen_pattern_file.py b/scripts/congestion-control/gen_pattern_file.py new file mode 100644 index 00000000..0b30bf3f --- /dev/null +++ b/scripts/congestion-control/gen_pattern_file.py @@ -0,0 +1,101 @@ +# Copyright (c) Neil McGlohon 2019 +# Rensselaer Polytechnic Institute +# This script is an example pattern generator for use with the congestion controller module +# in CODES. It generates patterns, one per line, that when matched, indicate that the network +# is in a state of congestion. These patterns are used by the supervisory controller, looking +# at the last N number of measurement periods (epochs) for whether the ports or NICs experienced +# congestion, if the pattern of the last N measurement periods matches any pattern provided by +# this file, then congestion has been detected in the network. +# This is a brute force attempt but since these files only need to be generated once, it's not +# so important that this be the most optimized that it could be. + +#NOTE: 6-6-2021 DEPRECATED - This was necessary for v1 of the congestion control feature. This version was +# not great and part of the reason was that it relied on patterns like these for detection +# of congestion. This file will eventually be removed entirely from the repo but was left +# as a monument to my wasted time. Congestion Control v1 was wiped and replaced by v2. + +import sys + +N_PERIODS = 5 #length of patterns +MIN_TO_INDICATE = 3 #how many measurement periods must be 'congested' for the network to consider itself in a state of congestion +HISTERISIS = 3 #how many time periods must be empty starting from the latest for the network to consider itself rid of congestion +QUIET = True + +def log(s): + if not QUIET: + print(s) + + +def check_valid_congestion_pattern(pattern): + # print("Checking: %s"%pattern) + + num_ones = pattern.count('1') + if num_ones < MIN_TO_INDICATE: + log("NOT CONGESTION: %s"%pattern) + return False + + num_ones_in_histerisis_window = pattern[-HISTERISIS:].count('1') + if num_ones_in_histerisis_window < 1: + log("NOT CONGESTION: %s"%pattern) + return False + + log("CONGESTION: %s"%pattern) + return True + +def check_valid_decongestion_pattern(pattern): + + num_ones_in_histerisis_window = pattern[-HISTERISIS:].count('1') + if num_ones_in_histerisis_window < 1: + log("DECONGESTION: %s"%pattern) + return True + +def generate_patterns(): + valid_congestion_patterns = [] + valid_decongestion_patterns = [] + + format_specifier = '#0%db'%(N_PERIODS+2) + max_number = 2**N_PERIODS + for i in range(max_number): + pattern = format(i, format_specifier)[2:] + + if check_valid_congestion_pattern(pattern): + valid_congestion_patterns.append(pattern) + + if check_valid_decongestion_pattern(pattern): + valid_decongestion_patterns.append(pattern) + + return (valid_congestion_patterns, valid_decongestion_patterns) + +def write_patterns(filename, patterns): + with open(filename,"w") as f: + for pattern in patterns: + # log("Writing: %s"%pattern) + f.write(pattern+'\n') + +def main(): + if len(sys.argv) < 5: + print("Usage: python3 get_pattern_file.py (optional: --verbose)") + exit(1) + + global QUIET + if '--verbose' in sys.argv: + QUIET = False + + global N_PERIODS, MIN_TO_INDICATE, HISTERISIS + N_PERIODS = int(sys.argv[1]) + MIN_TO_INDICATE = int(sys.argv[2]) + HISTERISIS = int(sys.argv[3]) + congestion_filename = sys.argv[4] + decongestion_filename = sys.argv[5] + + + print("Generating: Length of Patterns=%d Minimum to Indicate=%d Histerisis=%d"%(N_PERIODS, MIN_TO_INDICATE, HISTERISIS)) + + (congestion_patterns, decongestion_patterns) = generate_patterns() + write_patterns(congestion_filename, congestion_patterns) + write_patterns(decongestion_filename, decongestion_patterns) + + print("Written to %s and %s"%(congestion_filename,decongestion_filename)) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/dragonfly-dally/dragonfly-dally-link-fail-gen.py b/scripts/dragonfly-dally/dragonfly-dally-link-fail-gen.py new file mode 100644 index 00000000..d4345110 --- /dev/null +++ b/scripts/dragonfly-dally/dragonfly-dally-link-fail-gen.py @@ -0,0 +1,445 @@ +# Copyright 2020 - Neil McGlohon +# mcglon@rpi.edu + +import sys +from enum import Enum +import struct +import numpy as np +import random +import scipy.sparse as sps +import scipy.linalg as la +from scipy.sparse import csgraph +argv = sys.argv +import math +DRYRUN = 0 +SPECTRAL = 0 +COMPONENTS = 0 + + +def get_assigned_router_id_from_terminal(params, term_gid, rail_id): + num_planes = params.num_planes + num_rails = params.num_injection_rails + + num_cn_conns_per_router = params.total_terminals / params.routers_per_plane + + if num_planes == 1: + if num_rails == 1: + return math.floor(term_gid / num_cn_conns_per_router) + else: #now just all rails go to same router - possibly change this later + return math.floor(term_gid / num_cn_conns_per_router) + else: + if num_planes == num_rails: + return math.floor((term_gid / num_cn_conns_per_router) + (rail_id * params.routers_per_plane)) + else: + print("different rails per plane not allowed - only rails == planes") + exit(0) + + + +class LinkType(Enum): + INTRA = 1 + INTER = 2 + TERMINAL = 3 + WILDROUTER = 4 + + +class Network(object): + def __init__(self, params): + self.link_list = [] + self.link_map = {} + self.adj_map = {} + + self.term_link_list = [] + self.term_link_map = {} + + self.num_intra_links = 0 + self.num_inter_links = 0 + self.num_terminal_links = 0 + + self.num_intra_failed = 0 + self.num_inter_failed = 0 + self.num_terminal_failed = 0 + + self.params = params + + def add_link(self, src_gid, dest_gid, plane_id, link_type): + id_set = frozenset([src_gid, dest_gid, link_type]) + + if id_set not in self.link_map: + # print("New Link %d -> %d"%(src_gid,dest_gid)) + new_link = Link(src_gid, dest_gid, plane_id, link_type) + self.link_map[id_set] = [new_link] + self.link_list.append(new_link) + elif id_set in self.link_map: + done = False + for link in self.link_map[id_set]: + if link.bi_link_added == False: + link.bi_link_added = True + done = True + # print("Complete %d <-> %d"%(src_gid,dest_gid)) + break + if not done: + # print("New Link %d -> %d"%(src_gid,dest_gid)) + new_link = Link(src_gid, dest_gid, plane_id, link_type) + self.link_map[id_set].append(new_link) + self.link_list.append(new_link) + + self.num_intra_links = len([link for link in self.link_list if link.link_type == LinkType.INTRA]) + self.num_inter_links = len([link for link in self.link_list if link.link_type == LinkType.INTER]) + + def add_term_link(self, router_gid, terminal_gid, rail_id): + id_set = frozenset([router_gid, terminal_gid, LinkType.TERMINAL]) + # num_existing_links = 0 + # if id_set in self.term_link_map: + # num_existing_links = len(self.term_link_map[id_set]) + + new_link = Link(router_gid, terminal_gid, rail_id, LinkType.TERMINAL) + + if id_set not in self.term_link_map: + self.term_link_map[id_set] = [new_link] + else: + self.term_link_map[id_set].append(new_link) + + # print("New Term Link r%d -> t%d"%(router_gid,terminal_gid), end=' ') + # print(id_set) + + self.term_link_list.append(new_link) + self.num_terminal_links += 1 + + def fail_links(self, link_type, percent_to_fail, plane_id = -1): + if link_type == LinkType.WILDROUTER: + if plane_id is -1: + links_to_consider = [link for link in self.link_list if link.link_type != LinkType.TERMINAL] + else: + links_to_consider = [link for link in self.link_list if link.rail_id == plane_id] + else: + if plane_id is -1: #then we don't care which plane it comes from + links_to_consider = [link for link in self.link_list if link.link_type == link_type] + else: #only fail from specific plane + links_to_consider = [link for link in self.link_list if link.link_type == link_type if link.rail_id == plane_id] + + num_to_fail = int(len(links_to_consider)*percent_to_fail) + + links_to_fail = random.sample(links_to_consider, k=num_to_fail) + + for link in links_to_fail: + link.is_failed = True + if link.link_type is LinkType.INTRA: + self.num_intra_failed += 1 + elif link.link_type is LinkType.INTER: + self.num_inter_failed += 1 + else: + self.num_terminal_failed += 1 + + def fail_term_links_safe(self, percent_to_fail): + if self.params.num_planes == 1: #then all rails on a router go to same terminal + for router_id in range(self.params.total_routers): + for tlid in range(self.params.num_hosts_per_router): + for i in range(self.params.num_injection_rails-1): #will always leave one rail untouched + fail_roll = random.random() + if fail_roll > percent_to_fail: + term_gid = self.params.num_hosts_per_router * router_id + tlid + + id_set = frozenset([router_id, term_gid, LinkType.TERMINAL]) + for link in self.term_link_map[id_set]: + if link.is_failed == 0: + link.is_failed = 1 + self.num_terminal_failed += 1 + break + + def get_adjacency_matrix(self, include_failed_links=False, plane_id=0): + A = np.zeros((self.params.routers_per_plane, self.params.routers_per_plane)) + rpp = self.params.routers_per_plane + + + for link in self.link_list: + if link.rail_id == plane_id: + if not include_failed_links: + if not link.is_failed: + A[link.src_gid%rpp,link.dest_gid%rpp] += 1 + A[link.dest_gid%rpp,link.src_gid%rpp] += 1 + else: + A[link.src_gid%rpp,link.dest_gid%rpp] += 1 + A[link.dest_gid%rpp,link.src_gid%rpp] += 1 + + return A + + def calc_adjacency_map(self, include_failed_links=False): + for link in self.link_list: + plane_id = link.rail_id + if link.is_failed: + continue + + if plane_id not in self.adj_map: + self.adj_map[plane_id] = {} + + if link.src_gid in self.adj_map[plane_id]: + self.adj_map[plane_id][link.src_gid].append(link.dest_gid) + else: + self.adj_map[plane_id][link.src_gid] = [link.dest_gid] + if link.dest_gid in self.adj_map[plane_id]: + self.adj_map[plane_id][link.dest_gid].append(link.src_gid) + else: + self.adj_map[plane_id][link.dest_gid] = [link.src_gid] + + + def get_laplacian(self, include_failed_links=False, plane_id=0): + A = self.get_adjacency_matrix(include_failed_links, plane_id) + L = csgraph.laplacian(A) + return L + + def dfs_recursive(self, gid, visited, plane_id): + visited[gid%self.params.routers_per_plane] = True + + for neighbor in self.adj_map[plane_id][gid]: + neighbor_pgid = neighbor % self.params.routers_per_plane + if visited[neighbor_pgid] == False: + self.dfs_recursive(neighbor, visited, plane_id) + + def is_connected(self, plane_id): + visited = [False] * (self.params.routers_per_plane) + try: + self.dfs_recursive(0+(plane_id*self.params.routers_per_plane), visited, plane_id) + except: + return False + + return all(visited) + + def __str__(self): + the_str = "" + for src_id in range(self.params.total_routers): + for dest_id in range(self.params.total_routers): + id_set = frozenset([src_id, dest_id, LinkType.INTRA]) + if id_set in self.link_map: + for link in self.link_map[id_set]: + the_str += "%d -> %d %s, Failed=%s\n"%(src_id, dest_id, str(link.link_type), str(link.is_failed)) + + for src_id in range(self.params.total_routers): + for dest_id in range(self.params.total_routers): + id_set = frozenset([src_id, dest_id, LinkType.INTER]) + if id_set in self.link_map: + for link in self.link_map[id_set]: + the_str += "%d -> %d %s, Failed=%s\n"%(src_id, dest_id, str(link.link_type), str(link.is_failed)) + + + return the_str + +class Params(object): + def __init__(self, radix, num_conn_between_groups, total_terminals, num_injection_rails, num_planes, failure_mode): + self.router_radix = radix + self.num_conn_between_groups = num_conn_between_groups + self.total_terminals = total_terminals + self.num_injection_rails = num_injection_rails + self.num_planes = num_planes + + self.num_routers_per_group = int((radix + 1)/2) #a = (radix + 1)/2 + self.num_gc_per_router = int(self.num_routers_per_group // 2) + self.num_gc_per_group = self.num_gc_per_router * self.num_routers_per_group + + num_gc_per_group = self.num_gc_per_router * self.num_routers_per_group + self.num_groups = int((num_gc_per_group / self.num_conn_between_groups)) + 1 + self.routers_per_plane = self.num_routers_per_group * self.num_groups + self.total_routers = self.routers_per_plane * self.num_planes + self.num_hosts_per_router = int(total_terminals / self.total_routers) + self.cn_radix = num_injection_rails * self.num_hosts_per_router + + self.failure_mode = failure_mode + + + def getSummary(self): + outStr = "\nDragonfly (Dally) Network:\n" + outStr += "\tNumber of Groups (per plane): %d\n" % self.num_groups + outStr += "\tRouter Radix: %d\n" % self.router_radix + outStr += "\tNumber Routers Per Group: %d\n" % self.num_routers_per_group + outStr += "\tNumber Terminal Per Router: %d\n" % self.num_hosts_per_router + outStr += "\n" + outStr += "\tNumber Term Links per Router: %d\n" % self.cn_radix + outStr += "\n" + outStr += "\tNumber GC per Router: %d\n" % self.num_gc_per_router + outStr += "\tNumber GC per Group: %d\n" % self.num_gc_per_group + outStr += "\tNumber GC between Groups: %d\n" % self.num_conn_between_groups + outStr += "\n" + outStr += "\tNum Routers per plane: %d\n" % self.routers_per_plane + outStr += "\tTotal Routers: %d\n" % self.total_routers + outStr += "\tTotal Number Terminals: %d\n" % (self.total_terminals) + outStr += "\t" + return outStr + +class Link(object): + def __init__(self, src_gid, dest_gid, rail_id, link_type): + self.src_gid = src_gid + self.dest_gid = dest_gid + self.link_type = link_type + self.rail_id = rail_id + self.is_failed = False + self.bi_link_added = False # so I can keep track of parallel links, if this is true, and we try to add a link that matches this one, then a new one must be created + + def fail_link(self): + self.is_failed = True + + + +def main(): + global DRYRUN, SPECTRAL, COMPONENTS + if "--dryrun" in argv: + DRYRUN = 1 + if "--spectral" in argv: + SPECTRAL = 1 + if "--components" in argv: + COMPONENTS = 1 + + if(len(argv) < 9): + raise Exception("Correct usage: python %s " % sys.argv[0]) + + router_radix = int(argv[1]) + num_conn_between_groups = int(argv[2]) + num_terminals = int(argv[3]) + num_injection_rails = int(argv[4]) + num_planes = int(argv[5]) + percent_to_fail = float(argv[6]) + # percent_intra_fail = float(argv[6]) + # percent_inter_fail = float(argv[7]) + + + params = Params(router_radix, num_conn_between_groups, num_terminals, num_injection_rails, num_planes, 1) + net = Network(params) + + print(params.getSummary()) + + + if not DRYRUN: + with open(argv[7],"rb") as intra: + loadIntra(params, intra, net) + with open(argv[8],"rb") as inter: + loadInter(params, inter, net) + + add_terminal_links(params, net) + + net.fail_links(LinkType.WILDROUTER, percent_to_fail, -1) #fail any link, with a given percentage total, from any plane + # net.fail_links(LinkType.INTRA, percent_intra_fail, 0) + # net.fail_links(LinkType.INTER, percent_inter_fail, 0) + # net.fail_term_links_safe(.5) + + # print(net) + + meta_content = "" + meta_content += params.getSummary() + '\n' + meta_content += "Number Intra Failed %d/%d\n"%(net.num_intra_failed, net.num_intra_links) + meta_content += "Number Inter Failed %d/%d\n"%(net.num_inter_failed, net.num_inter_links) + meta_content += "Number Term Failed %d/%d\n"%(net.num_terminal_failed, net.num_terminal_links) + + with open(argv[9],"wb") as failfd: + meta_content += writeFailed(params, failfd, net) + "\n" + + net.calc_adjacency_map() + for p in range(params.num_planes): + + is_connected = net.is_connected(p) + + if is_connected: + outstr = "Plane %d is Connected "%p + meta_content += outstr + else: + outstr = "Plane %d is Disconnected "%p + meta_content += outstr + + if (COMPONENTS): + n_components = csgraph.connected_components(net.get_adjacency_matrix(plane_id=p), return_labels=False) + outstr = "calculated %d components, "%(n_components) + meta_content += outstr + + + if (SPECTRAL): + L = net.get_laplacian(include_failed_links=False,plane_id=p) + eigs = la.eigvals(L) + eigs = sorted(eigs) + connectivity = np.real(eigs[1]) + outstr = "calculated %.9f 2nd lowest eigenvalue (real-part) "%connectivity + meta_content += outstr + + meta_content += "\n" + + print(meta_content) + + metafilename = argv[9] + "-meta" + with open(metafilename,"w") as metafd: + metafd.write(meta_content) + + +def loadIntra(params, fd, net): + intra_id_pairs = [] + + while(True): + buf = fd.read(12) + if not buf: + break + (src_lid, dest_lid, dummy) = struct.unpack("3i",buf) + intra_id_pairs.append((src_lid,dest_lid)) + + for p in range(params.num_planes): + for i in range(params.num_groups): + for pair in intra_id_pairs: + (src_lid,dest_lid) = pair + src_gid = (i * params.num_routers_per_group + src_lid) + (p*params.routers_per_plane) + dest_gid = (i * params.num_routers_per_group + dest_lid) + (p*params.routers_per_plane) + + net.add_link(src_gid, dest_gid, p, LinkType.INTRA) + + + +def loadInter(params, fd, net): + inter_id_pairs = [] + + while(True): + buf = fd.read(8) + if not buf: + break + (src_gid,dest_gid) = struct.unpack("2i",buf) + inter_id_pairs.append((src_gid,dest_gid)) + + for p in range(params.num_planes): + for pair in inter_id_pairs: + (src_pgid,dest_pgid) = pair + src_gid = src_pgid + (p*params.routers_per_plane) + dest_gid = dest_pgid + (p*params.routers_per_plane) + + net.add_link(src_gid, dest_gid, p, LinkType.INTER) + +def add_terminal_links(params, net): + total_terminals = params.total_terminals + num_rails = params.num_injection_rails + + for tgid in range(total_terminals): + for rail_id in range(num_rails): + assigned_router_id = get_assigned_router_id_from_terminal(params, tgid, rail_id) + # print("Gen r%d -> t%d rail %d"%(assigned_router_id, tgid,rail_id)) + net.add_term_link(assigned_router_id, tgid, rail_id) + + + + + +def writeFailed(params, fd, net): + failed_links = [link for link in net.link_list if link.is_failed] + failed_terms = [link for link in net.term_link_list if link.is_failed] + failed_links.extend(failed_terms) + + for link in failed_links: + src_gid = link.src_gid + dest_gid = link.dest_gid + rail_id = link.rail_id + link_type = link.link_type + + outstr = '' + fd.write(struct.pack("4i",src_gid, dest_gid, rail_id, link_type.value)) + if link_type is not LinkType.TERMINAL: #terminal link bidirectional is handled by the model + fd.write(struct.pack("4i",dest_gid, src_gid, rail_id, link_type.value)) + outstr+= "%d <-> %d rail=%d type=%s Failed\n"%(src_gid, dest_gid, rail_id, link_type) + print(outstr,end='') + + outstr = "Written %d failed bidirectional links (%d total written links)"%(len(failed_links),len(failed_links)*2) + print(outstr) + return outstr + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/dragonfly-plus/dragonfly-plus-link-fail-gen.py b/scripts/dragonfly-plus/dragonfly-plus-link-fail-gen.py new file mode 100644 index 00000000..2469f7a4 --- /dev/null +++ b/scripts/dragonfly-plus/dragonfly-plus-link-fail-gen.py @@ -0,0 +1,466 @@ +# Copyright 2020 - Neil McGlohon +# mcglon@rpi.edu + +import sys +from enum import Enum +import struct +import numpy as np +import random +import scipy.sparse as sps +import scipy.linalg as la +from scipy.sparse import csgraph +argv = sys.argv +import math +DRYRUN = 0 +SPECTRAL = 0 +COMPONENTS = 0 + + +def get_assigned_router_id_from_terminal(params, term_gid, rail_id): + num_planes = params.num_planes + num_rails = params.num_injection_rails + num_cn_per_group = params.num_leaf_per_group * params.num_hosts_per_leaf + + group_id = int(term_gid / num_cn_per_group) + planar_group_id = int(group_id % params.num_groups) + local_router_id = int(term_gid / params.num_hosts_per_leaf) % params.num_leaf_per_group + router_id_on_plane_0 = int(planar_group_id * params.num_routers_per_group) + local_router_id + + if num_planes == 1: + if num_rails == 1: + return int(router_id_on_plane_0) + + else: #now just all rails go to same router - possibly change this later + return int(router_id_on_plane_0) + else: + rpp = params.total_routers / params.num_planes + if num_planes == num_rails: + return int(router_id_on_plane_0 + (rail_id * rpp)) + else: + print("different rails per plane not allowed - only rails == planes") + exit(0) + + + +class LinkType(Enum): + INTRA = 1 + INTER = 2 + TERMINAL = 3 + WILDROUTER = 4 + + + +class Network(object): + def __init__(self, params): + self.link_list = [] + self.link_map = {} + self.adj_map = {} + + self.term_link_list = [] + self.term_link_map = {} + + self.num_intra_links = 0 + self.num_inter_links = 0 + self.num_terminal_links = 0 + + self.num_intra_failed = 0 + self.num_inter_failed = 0 + self.num_terminal_failed = 0 + + self.params = params + + def add_link(self, src_gid, dest_gid, plane_id, link_type): + id_set = frozenset([src_gid, dest_gid, link_type]) + + if id_set not in self.link_map: + # print("New Link %d -> %d"%(src_gid,dest_gid)) + new_link = Link(src_gid, dest_gid, plane_id, link_type) + self.link_map[id_set] = [new_link] + self.link_list.append(new_link) + elif id_set in self.link_map: + done = False + for link in self.link_map[id_set]: + if link.bi_link_added == False: + link.bi_link_added = True + done = True + # print("Complete %d <-> %d"%(src_gid,dest_gid)) + break + if not done: + # print("New Link %d -> %d"%(src_gid,dest_gid)) + new_link = Link(src_gid, dest_gid, plane_id, link_type) + self.link_map[id_set].append(new_link) + self.link_list.append(new_link) + + self.num_intra_links = len([link for link in self.link_list if link.link_type == LinkType.INTRA]) + self.num_inter_links = len([link for link in self.link_list if link.link_type == LinkType.INTER]) + + def add_term_link(self, router_gid, terminal_gid, rail_id): + id_set = frozenset([router_gid, terminal_gid, LinkType.TERMINAL]) + # num_existing_links = 0 + # if id_set in self.term_link_map: + # num_existing_links = len(self.term_link_map[id_set]) + + new_link = Link(router_gid, terminal_gid, rail_id, LinkType.TERMINAL) + + if id_set not in self.term_link_map: + self.term_link_map[id_set] = [new_link] + else: + self.term_link_map[id_set].append(new_link) + + # print("New Term Link r%d -> t%d"%(router_gid,terminal_gid), end=' ') + # print(id_set) + + self.term_link_list.append(new_link) + self.num_terminal_links += 1 + + def fail_links(self, link_type, percent_to_fail, plane_id = -1): + if link_type == LinkType.WILDROUTER: + if plane_id is -1: + links_to_consider = [link for link in self.link_list if link.link_type != LinkType.TERMINAL] + else: + links_to_consider = [link for link in self.link_list if link.rail_id == plane_id] + else: + if plane_id is -1: #then we don't care which plane it comes from + links_to_consider = [link for link in self.link_list if link.link_type == link_type] + else: #only fail from specific plane + links_to_consider = [link for link in self.link_list if link.link_type == link_type if link.rail_id == plane_id] + + num_to_fail = int(len(links_to_consider)*percent_to_fail) + + links_to_fail = random.sample(links_to_consider, k=num_to_fail) + + for link in links_to_fail: + link.is_failed = True + if link.link_type is LinkType.INTRA: + self.num_intra_failed += 1 + elif link.link_type is LinkType.INTER: + self.num_inter_failed += 1 + else: + self.num_terminal_failed += 1 + + def fail_term_links_safe(self, percent_to_fail): + if self.params.num_planes == 1: #then all rails on a router go to same terminal + for router_id in range(self.params.total_routers): + for tlid in range(self.params.num_hosts_per_leaf): + for i in range(self.params.num_injection_rails-1): #will always leave one rail untouched + fail_roll = random.random() + if fail_roll > percent_to_fail: + term_gid = self.params.num_hosts_per_leaf * router_id + tlid + + id_set = frozenset([router_id, term_gid, LinkType.TERMINAL]) + for link in self.term_link_map[id_set]: + if link.is_failed == 0: + link.is_failed = 1 + self.num_terminal_failed += 1 + break + + def get_adjacency_matrix(self, include_failed_links=False, plane_id=0): + A = np.zeros((self.params.routers_per_plane, self.params.routers_per_plane)) + rpp = self.params.routers_per_plane + + + for link in self.link_list: + if link.rail_id == plane_id: + if not include_failed_links: + if not link.is_failed: + A[link.src_gid%rpp,link.dest_gid%rpp] += 1 + A[link.dest_gid%rpp,link.src_gid%rpp] += 1 + else: + A[link.src_gid%rpp,link.dest_gid%rpp] += 1 + A[link.dest_gid%rpp,link.src_gid%rpp] += 1 + + return A + + def calc_adjacency_map(self, include_failed_links=False): + for link in self.link_list: + plane_id = link.rail_id + if link.is_failed: + continue + + if plane_id not in self.adj_map: + self.adj_map[plane_id] = {} + + if link.src_gid in self.adj_map[plane_id]: + self.adj_map[plane_id][link.src_gid].append(link.dest_gid) + else: + self.adj_map[plane_id][link.src_gid] = [link.dest_gid] + if link.dest_gid in self.adj_map[plane_id]: + self.adj_map[plane_id][link.dest_gid].append(link.src_gid) + else: + self.adj_map[plane_id][link.dest_gid] = [link.src_gid] + + + def get_laplacian(self, include_failed_links=False, plane_id=0): + A = self.get_adjacency_matrix(include_failed_links, plane_id) + L = csgraph.laplacian(A) + return L + + def dfs_recursive(self, gid, visited, plane_id): + visited[gid%self.params.routers_per_plane] = True + + for neighbor in self.adj_map[plane_id][gid]: + neighbor_pgid = neighbor % self.params.routers_per_plane + if visited[neighbor_pgid] == False: + self.dfs_recursive(neighbor, visited, plane_id) + + def is_connected(self, plane_id): + visited = [False] * (self.params.routers_per_plane) + try: + self.dfs_recursive(0+(plane_id*self.params.routers_per_plane), visited, plane_id) + except: + return False + + return all(visited) + + def __str__(self): + the_str = "" + for src_id in range(self.params.total_routers): + for dest_id in range(self.params.total_routers): + id_set = frozenset([src_id, dest_id, LinkType.INTRA]) + if id_set in self.link_map: + for link in self.link_map[id_set]: + the_str += "%d -> %d %s, Failed=%s\n"%(src_id, dest_id, str(link.link_type), str(link.is_failed)) + + for src_id in range(self.params.total_routers): + for dest_id in range(self.params.total_routers): + id_set = frozenset([src_id, dest_id, LinkType.INTER]) + if id_set in self.link_map: + for link in self.link_map[id_set]: + the_str += "%d -> %d %s, Failed=%s\n"%(src_id, dest_id, str(link.link_type), str(link.is_failed)) + + + return the_str + +class Params(object): + def __init__(self, radix, num_conn_between_groups, total_terminals, num_injection_rails, num_planes, failure_mode): + self.router_radix = radix + self.num_conn_between_groups = num_conn_between_groups + self.total_terminals = total_terminals + self.num_injection_rails = num_injection_rails + self.num_planes = num_planes + + self.num_routers_per_group = int((radix)) #a = (radix + 1)/2 + self.num_spine_per_group = self.num_routers_per_group/2 + self.num_leaf_per_group = self.num_spine_per_group + self.num_gc_per_spine = int(self.num_routers_per_group // 2) + self.num_gc_per_group = self.num_gc_per_spine * self.num_spine_per_group + + largest_num_groups = (radix//2)**2 + 1 + num_groups = (largest_num_groups - 1) // num_conn_between_groups + 1 + + self.num_groups = num_groups + self.routers_per_plane = self.num_routers_per_group * self.num_groups + self.total_routers = self.routers_per_plane * self.num_planes + self.num_hosts_per_leaf = int(total_terminals / (self.total_routers/2)) + self.cn_radix = num_injection_rails * self.num_hosts_per_leaf + + self.failure_mode = failure_mode + + + def getSummary(self): + outStr = "\nDragonfly (Dally) Network:\n" + outStr += "\tNumber of Groups (per plane): %d\n" % self.num_groups + outStr += "\tRouter Radix: %d\n" % self.router_radix + outStr += "\tNumber Spine Per Group: %d\n" % self.num_spine_per_group + outStr += "\tNumber Leaf Per Group: %d\n" % self.num_spine_per_group + outStr += "\tNumber Terminal Per Leaf: %d\n" % self.num_hosts_per_leaf + outStr += "\n" + outStr += "\tNumber Term Links per Router: %d\n" % self.cn_radix + outStr += "\n" + outStr += "\tNumber GC per Router: %d\n" % self.num_gc_per_spine + outStr += "\tNumber GC per Group: %d\n" % self.num_gc_per_group + outStr += "\tNumber GC between Groups: %d\n" % self.num_conn_between_groups + outStr += "\n" + outStr += "\tNum Routers per plane: %d\n" % self.routers_per_plane + outStr += "\tTotal Routers: %d\n" % self.total_routers + outStr += "\tTotal Number Terminals: %d\n" % (self.total_terminals) + outStr += "\t" + return outStr + +class Link(object): + def __init__(self, src_gid, dest_gid, rail_id, link_type): + self.src_gid = src_gid + self.dest_gid = dest_gid + self.link_type = link_type + self.rail_id = rail_id + self.is_failed = False + self.bi_link_added = False # so I can keep track of parallel links, if this is true, and we try to add a link that matches this one, then a new one must be created + + def fail_link(self): + self.is_failed = True + + def __lt__(self, other): + return (self.src_gid < other.src_gid) + + def __str__(self): + return "srcgid: %d destgid: %d type: %s is_failed: %d"%(self.src_gid,self.dest_gid,self.link_type,self.is_failed) + + +def main(): + global DRYRUN, SPECTRAL, COMPONENTS + if "--dryrun" in argv: + DRYRUN = 1 + if "--spectral" in argv: + SPECTRAL = 1 + if "--components" in argv: + COMPONENTS = 1 + + if(len(argv) < 9): + raise Exception("Correct usage: python %s " % sys.argv[0]) + + router_radix = int(argv[1]) + num_conn_between_groups = int(argv[2]) + num_terminals = int(argv[3]) + num_injection_rails = int(argv[4]) + num_planes = int(argv[5]) + percent_to_fail = float(argv[6]) + # percent_intra_fail = float(argv[6]) + # percent_inter_fail = float(argv[7]) + + params = Params(router_radix, num_conn_between_groups, num_terminals, num_injection_rails, num_planes, 1) + net = Network(params) + + print(params.getSummary()) + + + if not DRYRUN: + with open(argv[7],"rb") as intra: + loadIntra(params, intra, net) + with open(argv[8],"rb") as inter: + loadInter(params, inter, net) + + add_terminal_links(params, net) + + net.fail_links(LinkType.WILDROUTER, percent_to_fail, -1) #fail any link, with a given percentage total, from any plane + # net.fail_links(LinkType.INTRA, percent_intra_fail, 0) + # net.fail_links(LinkType.INTER, percent_inter_fail, 0) + # net.fail_term_links_safe(.5) + + # print(net) + + meta_content = "" + meta_content += params.getSummary() + '\n' + meta_content += "Number Intra Failed %d/%d\n"%(net.num_intra_failed, net.num_intra_links) + meta_content += "Number Inter Failed %d/%d\n"%(net.num_inter_failed, net.num_inter_links) + meta_content += "Number Term Failed %d/%d\n"%(net.num_terminal_failed, net.num_terminal_links) + + with open(argv[9],"wb") as failfd: + meta_content += writeFailed(params, failfd, net) + "\n" + + net.calc_adjacency_map() + for p in range(params.num_planes): + + is_connected = net.is_connected(p) + + if is_connected: + outstr = "Plane %d is Connected "%p + meta_content += outstr + else: + outstr = "Plane %d is Disconnected "%p + meta_content += outstr + + if (COMPONENTS): + n_components = csgraph.connected_components(net.get_adjacency_matrix(plane_id=p), return_labels=False) + outstr = "calculated %d components, "%(n_components) + meta_content += outstr + + + if (SPECTRAL): + L = net.get_laplacian(include_failed_links=False,plane_id=p) + eigs = la.eigvals(L) + eigs = sorted(eigs) + connectivity = np.real(eigs[1]) + outstr = "calculated %.9f 2nd lowest eigenvalue (real-part) "%connectivity + meta_content += outstr + + meta_content += "\n" + + print(meta_content) + + metafilename = argv[9] + "-meta" + with open(metafilename,"w") as metafd: + metafd.write(meta_content) + +def loadIntra(params, fd, net): + intra_id_pairs = [] + + while(True): + buf = fd.read(8) + if not buf: + break + (src_lid, dest_lid) = struct.unpack("2i",buf) + intra_id_pairs.append((src_lid,dest_lid)) + + # print("loaded %d intra links"%len(intra_id_pairs)) + # print(intra_id_pairs) + + for p in range(params.num_planes): + for i in range(params.num_groups): + for pair in intra_id_pairs: + (src_lid,dest_lid) = pair + src_gid = (i * params.num_routers_per_group + src_lid) + (p*params.routers_per_plane) + dest_gid = (i * params.num_routers_per_group + dest_lid) + (p*params.routers_per_plane) + + net.add_link(src_gid, dest_gid, p, LinkType.INTRA) + + + +def loadInter(params, fd, net): + inter_id_pairs = [] + + while(True): + buf = fd.read(8) + if not buf: + break + (src_gid,dest_gid) = struct.unpack("2i",buf) + inter_id_pairs.append((src_gid,dest_gid)) + + for p in range(params.num_planes): + for pair in inter_id_pairs: + (src_pgid,dest_pgid) = pair + src_gid = src_pgid + (p*params.routers_per_plane) + dest_gid = dest_pgid + (p*params.routers_per_plane) + + net.add_link(src_gid, dest_gid, p, LinkType.INTER) + +def add_terminal_links(params, net): + total_terminals = params.total_terminals + num_rails = params.num_injection_rails + + for tgid in range(total_terminals): + for rail_id in range(num_rails): + assigned_router_id = get_assigned_router_id_from_terminal(params, tgid, rail_id) + # print("Gen r%d -> t%d rail %d"%(assigned_router_id, tgid,rail_id)) + net.add_term_link(assigned_router_id, tgid, rail_id) + + + + + +def writeFailed(params, fd, net): + failed_links = [link for link in net.link_list if link.is_failed] + failed_terms = [link for link in net.term_link_list if link.is_failed] + failed_links.extend(failed_terms) + + # for link in failed_interlinks: + # print(str(link)) + + for link in sorted(failed_links): + src_gid = link.src_gid + dest_gid = link.dest_gid + rail_id = link.rail_id + link_type = link.link_type + + outstr = '' + fd.write(struct.pack("4i",src_gid, dest_gid, rail_id, link_type.value)) + if link_type is not LinkType.TERMINAL: #terminal link bidirectional is handled by the model + fd.write(struct.pack("4i",dest_gid, src_gid, rail_id, link_type.value)) + outstr+= "%d <-> %d rail=%d type=%s Failed\n"%(src_gid, dest_gid, rail_id, link_type) + print(outstr,end='') + + outstr = "Written %d failed bidirectional links (%d total written links)"%(len(failed_links),len(failed_links)*2) + print(outstr) + return outstr + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..d7d34112 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,192 @@ +cmake_print_variables(CMAKE_CURRENT_SOURCE_DIR) + +find_package(FLEX REQUIRED) +find_package(BISON REQUIRED) + +flex_target(codes_lexer ${CMAKE_CURRENT_SOURCE_DIR}/modelconfig/configlex.l ${CMAKE_CURRENT_SOURCE_DIR}/modelconfig/configlex.c DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/modelconfig/configlex.h) +bison_target(codes_parser ${CMAKE_CURRENT_SOURCE_DIR}/modelconfig/configparser.y ${CMAKE_CURRENT_SOURCE_DIR}/modelconfig/configparser.c DEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/modelconfig/configparser.h) +ADD_FLEX_BISON_DEPENDENCY(codes_lexer codes_parser) + +cmake_print_variables(FLEX_codes_lexer_OUTPUTS) +cmake_print_variables(BISON_codes_parser_OUTPUTS) + +list(APPEND SRCS + networks/model-net/core/model-net.c + networks/model-net/core/model-net-lp.c + networks/model-net/core/model-net-sched.c + networks/model-net/core/model-net-sched-impl.c + + networks/model-net/common-net.c + networks/model-net/simplenet-upd.c + networks/model-net/torus.c + networks/model-net/express-mesh.C + networks/model-net/dragonfly.c + networks/model-net/dragonfly-custom.C + networks/model-net/dragonfly-plus.C + networks/model-net/dragonfly-dally.C + networks/model-net/slimfly.c + networks/model-net/fattree.c + networks/model-net/loggp.c + networks/model-net/simplep2p.c + + networks/model-net/network-managers/dragonfly-network-manager.C + + workload/codes-workload.c + workload/methods/codes-iolang-wrkld.c + workload/methods/codes-checkpoint-wrkld.c + workload/methods/test-workload-method.c + workload/methods/codes-iomock-wrkld.c + + util/codes_mapping.c + util/lp-type-lookup.c + util/lp-io.c + util/lp-msg.c + util/lookup3.c + util/resource.c + util/resource-lp.c + util/local-storage-model.c + util/codes-jobmap-method-impl.h + util/codes-jobmap.c + util/jobmap-impl/jobmap-dummy.c + util/jobmap-impl/jobmap-list.c + util/jobmap-impl/jobmap-identity.c + util/codes-mapping-context.c + util/codes-comm.c + util/rc-stack.c + util/congestion-controller.C + + iokernellang/codesparser.h + iokernellang/codesparser.c + iokernellang/codeslexer.h + iokernellang/codeslexer.c + iokernellang/codesImpl.c + iokernellang/CodesIOKernelContext.h + iokernellang/CodesIOKernelParser.h + iokernellang/CodesIOKernelTypes.h + iokernellang/CodesKernelHelpers.h + iokernellang/CodesKernelHelpers.c + + ${FLEX_codes_lexer_OUTPUTS} + ${BISON_codes_parser_OUTPUTS} + + modelconfig/configfile.c + modelconfig/configglue.h + modelconfig/configglue.c + modelconfig/configstore.h + modelconfig/configstore.c + modelconfig/configstoreadapter.h + modelconfig/configstoreadapter.c + modelconfig/configuration.c + modelconfig/txt_configfile.h + modelconfig/txt_configfile.c +) + +list(APPEND LIBS_TO_LINK PkgConfig::ROSS) + +if(USE_DUMPI) + list(APPEND SRCS workload/methods/codes-dumpi-trace-nw-wrkld.c) + list(APPEND LIBS_TO_LINK ${DUMPI_LIB}) +endif() + +if(USE_ONLINE) + list(APPEND SRCS workload/methods/codes-online-comm-wrkld.C) + list(APPEND LIBS_TO_LINK PkgConfig::SWM) + list(APPEND LIBS_TO_LINK PkgConfig::ARGOBOTS) +endif() + + +if(USE_RECORDER) + list(APPEND SRCS workload/methods/codes-recorder-io-wrkld.c) +endif() + +# if(USE_DARSHAN) +# list(APPEND SRCS workload/methods/codes-darshan3-io-wrkld.c) +# endif() + +add_library(codes STATIC ${SRCS}) + +list(APPEND LIBS_TO_LINK ${MPI_C_LIBRARIES}) +target_include_directories(codes INTERFACE ${MPI_C_INCLUDE_PATH}) + +# set(LIBS_TO_LINK +# PkgConfig::ROSS +# ${DUMPI_LIB} +# PkgConfig::ARGOBOTS +# PkgConfig::SWM +# ) + +#LINK DUMPI +# target_link_libraries(codes PUBLIC ${DUPMI_LIB}) +if(USE_DUMPI) + target_include_directories(codes PUBLIC ${DUMPI_INCLUDE}) +endif() + +#LINK ARGOBOTS and SWM ONLINE +# target_link_libraries(codes PUBLIC PkgConfig::ARGOBOTS) +if(USE_ONLINE) + target_include_directories(codes PUBLIC ${ARGOBOTS_INCLUDE_DIRS}) + # target_link_libraries(codes PUBLIC PkgConfig::SWM) + target_include_directories(codes PUBLIC ${SWM_INCLUDE_DIRS}) +endif() + +#LINK ROSS +# target_link_libraries(codes PUBLIC #{pkgcfg_lib_ROSS_ROSS}) +# target_link_libraries(codes PUBLIC PkgConfig::ROSS) +target_include_directories(codes PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${ROSS_INCLUDE_DIRS} + ${PROJECT_BINARY_DIR} + ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/codes + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/src/modelconfig +) + +target_link_libraries(codes PUBLIC ${LIBS_TO_LINK}) + +get_target_property(CODES_INCLUDE_DIRS codes INCLUDE_DIRECTORIES) +cmake_print_variables(CODES_INCLUDE_DIRS) + +add_executable(topology-test networks/model-net/topology-test.c) +add_executable(model-net-mpi-replay network-workloads/model-net-mpi-replay.c network-workloads/model-net-mpi-replay-main.c) +if(USE_DUMPI) + add_executable(codes-workload-dump workload/codes-workload-dump.c) + add_executable(model-net-dumpi-traces-dump network-workloads/model-net-dumpi-traces-dump.c) +endif() +add_executable(model-net-synthetic network-workloads/model-net-synthetic.c) +add_executable(model-net-synthetic-slimfly network-workloads/model-net-synthetic-slimfly.c) +add_executable(model-net-synthetic-fattree network-workloads/model-net-synthetic-fattree.c) +add_executable(model-net-synthetic-dragonfly-all network-workloads/model-net-synthetic-dragonfly-all.c) + +set(CODES_TARGETS + topology-test + model-net-mpi-replay + model-net-synthetic + model-net-synthetic-slimfly + model-net-synthetic-fattree + model-net-synthetic-dragonfly-all +) + +if(USE_DUMPI) + list(APPEND CODES_TARGETS codes-workload-dump) + list(APPEND CODES_TARGETS model-net-dumpi-traces-dump) +endif() + +foreach(tar IN LISTS CODES_TARGETS) + target_include_directories(${tar} PUBLIC ${CODES_INCLUDE_DIRS} ${ROSS_INCLUDE_DIRS}) + target_link_libraries(${tar} PUBLIC codes ${LIBS_TO_LINK}) +endforeach() + + +# configure_file(modelconfig/configlex.c ${CMAKE_CURRENT_BINARY_DIR}/modelconfig/configlex.c COPYONLY) +# configure_file(modelconfig/configlex.h ${CMAKE_CURRENT_BINARY_DIR}/modelconfig/configlex.h COPYONLY) + +# configure_file(modelconfig/configparser.c ${CMAKE_CURRENT_BINARY_DIR}/modelconfig/configparser.c COPYONLY) +# configure_file(modelconfig/configparser.h ${CMAKE_CURRENT_BINARY_DIR}/modelconfig/configparser.h COPYONLY) + +install(DIRECTORY "${CMAKE_SOURCE_DIR}/codes" DESTINATION "${CMAKE_BINARY_DIR}") + +install(TARGETS ${CODES_TARGETS} DESTINATION bin) + +install(TARGETS codes ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) + diff --git a/src/Makefile.subdir b/src/Makefile.subdir index 7a7d1a6d..9342c919 100644 --- a/src/Makefile.subdir +++ b/src/Makefile.subdir @@ -92,7 +92,9 @@ nobase_include_HEADERS = \ codes/model-net-sched.h \ codes/model-net-sched-impl.h \ codes/model-net-inspect.h \ - codes/connection-manager.h \ + codes/congestion-controller-core.h \ + codes/congestion-controller-model.h \ + codes/network-manager/dragonfly-network-manager.h \ codes/net/common-net.h \ codes/net/dragonfly.h \ codes/net/dragonfly-custom.h \ @@ -151,7 +153,7 @@ src_libcodes_la_SOURCES = \ src/util/jobmap-impl/jobmap-identity.c\ src/util/codes-mapping-context.c \ src/util/codes-comm.c \ - src/util/connection-manager.C \ + src/util/congestion-controller.C \ src/workload/codes-workload.c \ src/workload/methods/codes-iolang-wrkld.c \ src/workload/methods/codes-checkpoint-wrkld.c \ @@ -159,6 +161,7 @@ src_libcodes_la_SOURCES = \ src/workload/methods/codes-iomock-wrkld.c \ codes/rc-stack.h \ src/util/rc-stack.c \ + src/networks/model-net/network-managers/dragonfly-network-manager.C \ src/networks/model-net/core/model-net.c \ src/networks/model-net/common-net.c \ src/networks/model-net/simplenet-upd.c \ diff --git a/src/cmake/SetupMPI.cmake b/src/cmake/SetupMPI.cmake new file mode 100644 index 00000000..c257cefa --- /dev/null +++ b/src/cmake/SetupMPI.cmake @@ -0,0 +1,77 @@ +############################################################################### +# Copyright (c) 2017, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# LLNL-CODE-725085 +# +# All rights reserved. +# +# This file is part of BLT. +# +# For additional details, please also read BLT/LICENSE. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the disclaimer below. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the disclaimer (as noted below) in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of the LLNS/LLNL nor the names of its contributors may +# be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, +# LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################### + +################################ +# MPI +################################ + +find_package(MPI) +message(STATUS "MPI C Compile Flags: ${MPI_C_COMPILE_FLAGS}") +message(STATUS "MPI C Include Path: ${MPI_C_INCLUDE_PATH}") +message(STATUS "MPI C Link Flags: ${MPI_C_LINK_FLAGS}") +message(STATUS "MPI C Libraries: ${MPI_C_LIBRARIES}") + +message(STATUS "MPI CXX Compile Flags: ${MPI_CXX_COMPILE_FLAGS}") +message(STATUS "MPI CXX Include Path: ${MPI_CXX_INCLUDE_PATH}") +message(STATUS "MPI CXX Link Flags: ${MPI_CXX_LINK_FLAGS}") +message(STATUS "MPI CXX Libraries: ${MPI_CXX_LIBRARIES}") + +message(STATUS "MPI Executable: ${MPIEXEC}") +message(STATUS "MPI Num Proc Flag: ${MPIEXEC_NUMPROC_FLAG}") + + +if (ENABLE_FORTRAN) + # Determine if we should use fortran mpif.h header or fortran mpi module + find_path(mpif_path + NAMES "mpif.h" + PATHS ${MPI_Fortran_INCLUDE_PATH} + NO_DEFAULT_PATH + ) + + if(mpif_path) + set(MPI_Fortran_USE_MPIF ON CACHE PATH "") + message(STATUS "Using MPI Fortran header: mpif.h") + else() + set(MPI_Fortran_USE_MPIF OFF CACHE PATH "") + message(STATUS "Using MPI Fortran module: mpi.mod") + endif() +endif() diff --git a/src/modelconfig/configstore.c b/src/modelconfig/configstore.c index 26988305..24618230 100644 --- a/src/modelconfig/configstore.c +++ b/src/modelconfig/configstore.c @@ -5,6 +5,7 @@ */ #include "codes_config.h" +#include #include #include #ifdef HAVE_MALLOC_H diff --git a/src/network-workloads/conf/dragonfly-custom/modelnet-test-dragonfly-1728-nodes.conf.in b/src/network-workloads/conf/dragonfly-custom/modelnet-test-dragonfly-1728-nodes.conf.in index c6f16da7..854d7045 100644 --- a/src/network-workloads/conf/dragonfly-custom/modelnet-test-dragonfly-1728-nodes.conf.in +++ b/src/network-workloads/conf/dragonfly-custom/modelnet-test-dragonfly-1728-nodes.conf.in @@ -41,7 +41,7 @@ PARAMS # bandwidth in GiB/s for compute node-router channels cn_bandwidth="16.0"; # ROSS message size - message_size="736"; + message_size="768"; # number of compute nodes connected to router, dictated by dragonfly config # file num_cns_per_router="2"; diff --git a/src/network-workloads/conf/modelnet-mpi-test-dfly-amg-216.conf b/src/network-workloads/conf/modelnet-mpi-test-dfly-amg-216.conf index 1361d055..7846c34f 100644 --- a/src/network-workloads/conf/modelnet-mpi-test-dfly-amg-216.conf +++ b/src/network-workloads/conf/modelnet-mpi-test-dfly-amg-216.conf @@ -23,6 +23,6 @@ PARAMS local_bandwidth="5.25"; global_bandwidth="4.7"; cn_bandwidth="5.25"; - message_size="736"; + message_size="768"; routing="adaptive"; } diff --git a/src/network-workloads/conf/modelnet-mpi-test-slimfly-min.conf b/src/network-workloads/conf/modelnet-mpi-test-slimfly-min.conf index b965052d..04f50489 100644 --- a/src/network-workloads/conf/modelnet-mpi-test-slimfly-min.conf +++ b/src/network-workloads/conf/modelnet-mpi-test-slimfly-min.conf @@ -31,6 +31,6 @@ PARAMS cn_bandwidth="9.0"; router_delay="0"; link_delay="0"; - message_size="736"; + message_size="768"; routing="minimal"; } diff --git a/src/network-workloads/conf/modelnet-mpi-test-torus.conf b/src/network-workloads/conf/modelnet-mpi-test-torus.conf index 68cca782..817134c6 100644 --- a/src/network-workloads/conf/modelnet-mpi-test-torus.conf +++ b/src/network-workloads/conf/modelnet-mpi-test-torus.conf @@ -10,7 +10,7 @@ LPGROUPS PARAMS { packet_size="512"; - message_size="736"; + message_size="768"; modelnet_order=( "torus" ); # scheduler options modelnet_scheduler="fcfs"; diff --git a/src/network-workloads/model-net-mpi-replay.c b/src/network-workloads/model-net-mpi-replay.c index 9f6488d9..a311eb45 100644 --- a/src/network-workloads/model-net-mpi-replay.c +++ b/src/network-workloads/model-net-mpi-replay.c @@ -12,18 +12,20 @@ #include "codes/configuration.h" #include "codes/codes_mapping.h" #include "codes/model-net.h" +#include "codes/model-net-lp.h" #include "codes/rc-stack.h" #include "codes/quicklist.h" #include "codes/quickhash.h" #include "codes/codes-jobmap.h" +#include "codes/congestion-controller-core.h" /* turning on track lp will generate a lot of output messages */ #define MN_LP_NM "modelnet_dragonfly_custom" #define CONTROL_MSG_SZ 64 #define TRACE -1 -#define MAX_WAIT_REQS 1024 +#define MAX_WAIT_REQS 2048 #define CS_LP_DBG 1 -#define RANK_HASH_TABLE_SZ 2000 +#define RANK_HASH_TABLE_SZ 8193 #define NW_LP_NM "nw-lp" #define lprintf(_fmt, ...) \ do {if (CS_LP_DBG) printf(_fmt, __VA_ARGS__);} while (0) @@ -31,6 +33,9 @@ #define COL_TAG 1235 #define BAR_TAG 1234 #define PRINT_SYNTH_TRAFFIC 1 +#define MAX_JOBS 64 +#define NEAR_ZERO .0001 //timestamp for use to be 'close to zero' but still allow progress, zero offset events are hard on the PDES engine +#define OUTPUT_MARKS 0 static int msg_size_hash_compare( void *key, struct qhash_head *link); @@ -58,8 +63,10 @@ char workload_file[8192]; char offset_file[8192]; static int wrkld_id; static int num_net_traces = 0; -static int priority_type = 0; +static int prioritize_collectives = 0; static int num_dumpi_traces = 0; +static int num_nonsyn_jobs = 0; +static int num_total_jobs = 0; static int64_t EAGER_THRESHOLD = 8192; // static int upper_threshold = 1048576; @@ -79,15 +86,31 @@ static int do_lp_io = 0; /* variables for loading multiple applications */ char workloads_conf_file[8192]; +char workloads_timer_file[8192]; +char workloads_period_file[8192]; char alloc_file[8192]; -int num_traces_of_job[5]; +int num_traces_of_job[MAX_JOBS]; +int is_job_synthetic[MAX_JOBS]; //0 if job is not synthetic 1 if job is +int qos_level_of_job[MAX_JOBS]; +float mean_interval_of_job[MAX_JOBS]; +long job_timer1[MAX_JOBS]; +long job_timer2[MAX_JOBS]; +int period_count[MAX_JOBS]; +long period_time[MAX_JOBS][64]; +float period_interval[MAX_JOBS][64]; +char file_name_of_job[MAX_JOBS][8192]; + +tw_stime max_elapsed_time_per_job[MAX_JOBS] = {0}; + +/* On-node delay variables */ tw_stime soft_delay_mpi = 2500; tw_stime nic_delay = 1000; tw_stime copy_per_byte_eager = 0.55; -char file_name_of_job[5][8192]; struct codes_jobmap_ctx *jobmap_ctx; struct codes_jobmap_params_list jobmap_p; +struct codes_jobmap_params_identity jobmap_ident_p; // for if an alloc file isn't supplied. + /* Variables for Cortex Support */ /* Matthieu's additions start */ @@ -103,7 +126,7 @@ typedef struct nw_message nw_message; typedef unsigned int dumpi_req_id; static int net_id = 0; -static float noise = 1.0; +// static float noise = 1.0; static int num_nw_lps = 0, num_mpi_lps = 0; static int num_syn_clients; @@ -160,7 +183,9 @@ enum MPI_NW_EVENTS CLI_BCKGND_FIN, CLI_BCKGND_ARRIVE, CLI_BCKGND_GEN, + CLI_BCKGND_CHANGE, CLI_NBR_FINISH, + CLI_OTHER_FINISH //received when another workload has finished }; /* type of synthetic traffic */ @@ -170,7 +195,8 @@ enum TRAFFIC NEAREST_NEIGHBOR = 2, /* sends message to the next node (potentially connected to the same router) */ ALLTOALL = 3, /* sends message to all other nodes */ STENCIL = 4, /* sends message to 4 nearby neighbors */ - PERMUTATION = 5 + PERMUTATION = 5, + BISECTION = 6 }; struct mpi_workload_sample { @@ -255,10 +281,14 @@ struct nw_state short wrkld_end; int app_id; int local_rank; + int qos_level; int synthetic_pattern; int is_finished; - int neighbor_completed; + int num_own_job_ranks_completed; //counted by the root rank 0 of a job + + //array of whether this rank knows other jobs are completed. + int * known_completed_jobs; struct rc_stack * processed_ops; struct rc_stack * processed_wait_op; @@ -343,6 +373,7 @@ struct nw_message // forward message handler int msg_type; int op_type; + int num_rngs; model_net_event_return event_rc; struct codes_workload_op * mpi_op; @@ -375,6 +406,7 @@ struct nw_message double saved_wait_time_sample; double saved_delay; double saved_delay_sample; + double saved_marker_time; int64_t saved_num_bytes; int saved_syn_length; unsigned long saved_prev_switch; @@ -506,7 +538,10 @@ static void notify_background_traffic_rc( int num_jobs = codes_jobmap_get_num_jobs(jobmap_ctx); for(int i = 0; i < num_jobs - 1; i++) - tw_rand_reverse_unif(lp->rng); + { + if(is_job_synthetic[i] == 0) + continue; + } } static void notify_background_traffic( @@ -525,8 +560,9 @@ static void notify_background_traffic( for(int other_id = 0; other_id < num_jobs; other_id++) { - if(other_id == jid.job) + if(is_job_synthetic[other_id] == 0) //we only want to notify the synthetic (background) ranks continue; + assert(other_id != jid.job); struct codes_jobmap_id other_jid; other_jid.job = other_id; @@ -534,7 +570,7 @@ static void notify_background_traffic( int num_other_ranks = codes_jobmap_get_num_ranks(other_id, jobmap_ctx); lprintf("\n Other ranks %d ", num_other_ranks); - tw_stime ts = (1.1 * g_tw_lookahead) + tw_rand_exponential(lp->rng, noise); + tw_stime ts = NEAR_ZERO; tw_lpid global_dest_id; for(int k = 0; k < num_other_ranks; k++) @@ -553,63 +589,201 @@ static void notify_background_traffic( } return; } -static void notify_neighbor_rc( - struct nw_state * ns, + +static void notify_root_workload_rc( + struct nw_state * ns, tw_lp * lp, tw_bf * bf, struct nw_message * m) { - if(bf->c0) - { - notify_background_traffic_rc(ns, lp, bf, m); - return; - } - - if(bf->c1) - { - tw_rand_reverse_unif(lp->rng); - } -} -static void notify_neighbor( - struct nw_state * ns, + (void)ns; + (void)bf; + (void)m; +} + +//notifies the lowest nonsynthetic job that this one has completed +//this is important for synthetic ranks that continue generating until all non-synthetic have completed +static void notify_root_workload( + struct nw_state * ns, tw_lp * lp, tw_bf * bf, struct nw_message * m) { - if(ns->local_rank == num_dumpi_traces - 1 - && ns->is_finished == 1 - && ns->neighbor_completed == 1) + (void)bf; + (void)m; + + struct codes_jobmap_id jid; + jid = codes_jobmap_to_local_id(ns->nw_id, jobmap_ctx); + + int num_jobs = codes_jobmap_get_num_jobs(jobmap_ctx); + + int lowest_non_synth_job_id; + for (int other_id = 0; other_id < num_jobs; other_id++) { -// printf("\n All workloads completed, notifying background traffic "); - bf->c0 = 1; - notify_background_traffic(ns, lp, bf, m); - return; + if (!is_job_synthetic[other_id]) { + lowest_non_synth_job_id = other_id; + break; + } + } + struct codes_jobmap_id other_jid; + other_jid.job = 0; + other_jid.rank = 0; //root rank + + int intm_dest_id = codes_jobmap_to_global_id(other_jid, jobmap_ctx); + tw_lpid global_dest_id = codes_mapping_get_lpid_from_relative(intm_dest_id, NULL, NW_LP_NM, NULL, 0); + + tw_event *e; + struct nw_message *m_new; + tw_stime ts = NEAR_ZERO; + e = tw_event_new(global_dest_id, ts, lp); + m_new = (struct nw_message*)tw_event_data(e); + m_new->msg_type = CLI_OTHER_FINISH; + m_new->fwd.app_id = ns->app_id; //just borrowing the fwd struct even though this isn't an injected message + tw_event_send(e); +} + +void handle_other_finish_rc( + struct nw_state * ns, + tw_lp * lp, + tw_bf * bf, + struct nw_message *m) +{ + ns->known_completed_jobs[m->fwd.app_id] = 0; + if(bf->c2) + notify_background_traffic_rc(ns, lp, bf, m); + +} + +//for nonsynthetic jobs to determine if they have all completed +//the highest ordered non synthetic job then notifies all synthetic ranks to stop generating traffic +void handle_other_finish( + struct nw_state * ns, + tw_lp * lp, + tw_bf * bf, + struct nw_message *m) +{ + // printf("APP %d RANK %d RECEIVED COMPLETION NOTICE\n",ns->app_id, ns->local_rank); + assert(ns->app_id == 0); //make sure that only the root workload is getting this notification + assert(ns->local_rank == 0); //make sure that only the root rank is getting this notification + + printf("App %d: Received finished workload notification",ns->app_id); + // if(is_job_synthetic[ns->app_id]) + // return; //nothing for synthetic (background) ranks to do here + // printf(" And I am not synthetic\n"); + int num_jobs = codes_jobmap_get_num_jobs(jobmap_ctx); + + ns->known_completed_jobs[m->fwd.app_id] = 1; + int total_completed_jobs = 0; + int total_non_syn_completed_jobs = 0; + + //Find number of completed non synthetic jobs + for(int i = 0; i < num_jobs; i++) + { + // if (is_job_synthetic[i] == 0) { + total_non_syn_completed_jobs += ns->known_completed_jobs[i]; + // } } - struct codes_jobmap_id nbr_jid; - nbr_jid.job = ns->app_id; - tw_lpid global_dest_id; + if (total_non_syn_completed_jobs == num_nonsyn_jobs) //then all nonsynthetic jobs have completed, the background synthetic workloads must be notified + { + printf("App %d: All non-synthetic workloads have completed\n", ns->app_id); + //Determine which job should be the one to notify all the background ranks + //Let's say: highest numbered non-synthetic job (found above) + // also make sure that there actually are synthetic jobs + if (total_non_syn_completed_jobs < num_jobs) + { + if(max_gen_data <= 0) { + printf("App %d: Notifying background traffic\n", ns->app_id); + bf->c2 = 1; + //If I am the last rank in the highest ordered non-synthetic job, then it is my job to notify + notify_background_traffic(ns, lp, bf, m); + } + else { + printf("App %d: Not notifying background traffic as max_gen_data > 0. Will let synthetic workloads finish",ns->app_id); + } + } - if(ns->is_finished == 1 && (ns->neighbor_completed == 1 || ns->local_rank == 0)) + //TODO because we're treating synthetic workloads differently based on whether or not there's max_gen_data set, creating this notification here at this exact spot in logic + //will result in LPs receiving a "wrap up" notification potentially before synthetic workloads are done. To fix this, then we need to start treating synthetic workloads + //with a max_gen_data set differently, so that they communicate with other workloads when they're done in the same way we do with regular workloads + //this notification would then be sent by a single workload LP that knows for a fact that all other workloads have completed. + //also this, to be more accurate, should only be sent when all of the workload LPs have received all messages that have been sent so that we know that no packets + //are currently in transit. This currently isn't measured for model_net_mpi_replay. + + //send to all non nw-lp LPs (all model net, is there a function taht does this?) + model_net_method_end_sim_broadcast(NEAR_ZERO, lp); + } + else { - bf->c1 = 1; + printf("There is still a nonsynethic workload left. %d != %d\n",total_non_syn_completed_jobs, num_nonsyn_jobs); + } +} -// printf("\n Local rank %d notifying neighbor %d ", ns->local_rank, ns->local_rank+1); - tw_stime ts = (1.1 * g_tw_lookahead) + tw_rand_exponential(lp->rng, noise); - nbr_jid.rank = ns->local_rank + 1; - - /* Send a notification to the neighbor about completion */ - int intm_dest_id = codes_jobmap_to_global_id(nbr_jid, jobmap_ctx); - global_dest_id = codes_mapping_get_lpid_from_relative(intm_dest_id, NULL, NW_LP_NM, NULL, 0); - - tw_event * e; - struct nw_message * m_new; - e = tw_event_new(global_dest_id, ts, lp); - m_new = (struct nw_message*)tw_event_data(e); - m_new->msg_type = CLI_NBR_FINISH; - tw_event_send(e); +static void handle_neighbor_finish_rc( + struct nw_state * ns, + tw_lp * lp, + tw_bf * bf, + struct nw_message *m) +{ + ns->num_own_job_ranks_completed--; + + if (bf->c1) { + notify_root_workload_rc(ns, lp, bf, m); + } +} + +//Called by the root rank of the application when it receives a rank completion notification from one of its own job's ranks +static void handle_neighbor_finish( + struct nw_state * ns, + tw_lp * lp, + tw_bf * bf, + struct nw_message *m) +{ + ns->num_own_job_ranks_completed++; + + //have all of the ranks from our job completed? + if (ns->num_own_job_ranks_completed == codes_jobmap_get_num_ranks(ns->app_id, jobmap_ctx)) { + bf->c1 = 1; + notify_root_workload(ns, lp, bf, m); } } + +static void notify_root_rank_rc( + struct nw_state * ns, + tw_lp * lp, + tw_bf * bf, + struct nw_message *m) +{ + +} + +static void notify_root_rank( + struct nw_state * ns, + tw_lp * lp, + tw_bf * bf, + struct nw_message *m) +{ + assert(ns->is_finished); + + tw_stime ts = NEAR_ZERO; + + struct codes_jobmap_id root_jid; + root_jid.job = ns->app_id; + root_jid.rank = 0; + tw_lpid global_dest_id; + + /* Send a notification to the root neighbor about completion */ + int intm_dest_id = codes_jobmap_to_global_id(root_jid, jobmap_ctx); + global_dest_id = codes_mapping_get_lpid_from_relative(intm_dest_id, NULL, NW_LP_NM, NULL, 0); + + tw_event * e; + struct nw_message * m_new; + e = tw_event_new(global_dest_id, ts, lp); + m_new = (struct nw_message*)tw_event_data(e); + m_new->msg_type = CLI_NBR_FINISH; + tw_event_send(e); +} + void finish_bckgnd_traffic_rc( struct nw_state * ns, tw_bf * b, @@ -632,32 +806,13 @@ void finish_bckgnd_traffic( (void)b; (void)msg; ns->is_finished = 1; - lprintf("\n LP %llu completed sending data %llu completed at time %lf ", LLU(lp->gid), ns->gen_data, tw_now(lp)); + ns->elapsed_time = tw_now(lp) - ns->start_time; + + printf("\n LP %llu App %d completed sending data %llu completed at time %lf ", LLU(lp->gid),ns->app_id, ns->gen_data, tw_now(lp)); return; } -void finish_nbr_wkld_rc( - struct nw_state * ns, - tw_bf * b, - struct nw_message * msg, - tw_lp * lp) -{ - ns->neighbor_completed = 0; - - notify_neighbor_rc(ns, lp, b, msg); -} - -void finish_nbr_wkld( - struct nw_state * ns, - tw_bf * b, - struct nw_message * msg, - tw_lp * lp) -{ - ns->neighbor_completed = 1; - - notify_neighbor(ns, lp, b, msg); -} static void gen_synthetic_tr_rc(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * lp) { if(bf->c0) @@ -681,13 +836,12 @@ static void gen_synthetic_tr_rc(nw_state * s, tw_bf * bf, nw_message * m, tw_lp s->num_bytes_sent -= payload_sz; s->ross_sample.num_bytes_sent -= payload_sz; } - tw_rand_reverse_unif(lp->rng); + // tw_rand_reverse_unif(lp->rng); s->num_sends--; s->ross_sample.num_sends--; if(bf->c5) - s->is_finished = 0; - + finish_bckgnd_traffic_rc(s, bf, m, lp); if(bf->c7) tw_rand_reverse_unif(lp->rng); } @@ -730,6 +884,7 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l case PERMUTATION: { m->rc.saved_prev_switch = s->prev_switch; //for reverse computation + m->rc.saved_perm = s->saved_perm_dest; length = 1; dest_svr = (int*) calloc(1, sizeof(int)); @@ -752,8 +907,6 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l dest_svr[0] = tw_rand_integer(lp->rng, 0, num_clients - 1); if(dest_svr[0] == s->local_rank) dest_svr[0] = (s->local_rank + num_clients/2) % num_clients; - /* TODO: Fix random number generation code */ - m->rc.saved_perm = s->saved_perm_dest; s->saved_perm_dest = dest_svr[0]; assert(s->saved_perm_dest != s->local_rank); } @@ -770,6 +923,13 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l dest_svr[0] = (s->local_rank + 1) % num_clients; } break; + case BISECTION: + { + length = 1; + dest_svr = (int*) calloc(1, sizeof(int)); + dest_svr[0] = (s->local_rank + (num_clients/2)) % num_clients; + } + break; case ALLTOALL: { dest_svr = (int*) calloc(num_clients-1, sizeof(int)); @@ -813,6 +973,31 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l /* Record length for reverse handler*/ m->rc.saved_syn_length = length; + char prio[12]; + switch(s->qos_level){ + case 0: + strcpy(prio, "high"); break; + case 1: + strcpy(prio, "medium"); break; + case 2: + strcpy(prio, "low"); break; + case 3: + strcpy(prio, "class3"); break; + case 4: + strcpy(prio, "class4"); break; + case 5: + strcpy(prio, "class5"); break; + default: + tw_error(TW_LOC, "\n Invalid QoS level: %d", s->qos_level); + break; + } + + // TODO: Check if I can combine these two if statements. -Kevin + if(tw_now(lp) < job_timer2[s->app_id] && job_timer1[s->app_id] > 0){ + if(tw_now(lp) > job_timer1[s->app_id]){ + length = 0; + } + } if(length > 0) { // m->event_array_rc = (model_net_event_return) malloc(length * sizeof(model_net_event_return)); @@ -832,7 +1017,7 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l remote_m.fwd.src_rank = s->local_rank; // printf("\nAPP %d SRC %d Dest %d (twid %llu)", jid.job, s->local_rank, dest_svr[i], global_dest_id); - m->event_rc = model_net_event(net_id, "medium", global_dest_id, payload_sz, 0.0, + m->event_rc = model_net_event(net_id, prio, global_dest_id, payload_sz, 0.0, sizeof(nw_message), (const void*)&remote_m, 0, NULL, lp); @@ -846,7 +1031,7 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l s->ross_sample.num_sends++; /* New event after MEAN_INTERVAL */ - tw_stime ts = mean_interval + tw_rand_exponential(lp->rng, noise); + tw_stime ts = mean_interval_of_job[s->app_id]; tw_event * e; nw_message * m_new; e = tw_event_new(lp->gid, ts, lp); @@ -857,7 +1042,7 @@ static void gen_synthetic_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * l if (max_gen_data != 0) { //max_gen_data is by default 0 (off). If it's on, then we use it to determine when to finish synth ranks if(s->gen_data >= max_gen_data) { bf->c5 = 1; - s->is_finished = 1; + finish_bckgnd_traffic(s, bf, m, lp); } } @@ -889,6 +1074,24 @@ void arrive_syn_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * lp) { (void)bf; (void)lp; + m->rc.saved_send_time = s->send_time; + m->rc.saved_send_time_sample = s->ross_sample.send_time; + if((tw_now(lp) - m->fwd.sim_start_time) > s->max_time) + { + m->rc.saved_prev_max_time = s->max_time; + s->max_time = tw_now(lp) - m->fwd.sim_start_time; + s->ross_sample.max_time = tw_now(lp) - m->fwd.sim_start_time; + } + + s->send_time += (tw_now(lp) - m->fwd.sim_start_time); + s->ross_sample.send_time += (tw_now(lp) - m->fwd.sim_start_time); + s->num_recvs++; + s->ross_sample.num_recvs++; + int data = m->fwd.num_bytes; + s->syn_data += data; + s->num_bytes_recvd += data; + s->ross_sample.num_bytes_recvd += data; + num_syn_bytes_recvd += data; if(PRINT_SYNTH_TRAFFIC) { if(s->local_rank == 0) @@ -908,24 +1111,6 @@ void arrive_syn_tr(nw_state * s, tw_bf * bf, nw_message * m, tw_lp * lp) }*/ } } - m->rc.saved_send_time = s->send_time; - m->rc.saved_send_time_sample = s->ross_sample.send_time; - if((tw_now(lp) - m->fwd.sim_start_time) > s->max_time) - { - m->rc.saved_prev_max_time = s->max_time; - s->max_time = tw_now(lp) - m->fwd.sim_start_time; - s->ross_sample.max_time = tw_now(lp) - m->fwd.sim_start_time; - } - - s->send_time += (tw_now(lp) - m->fwd.sim_start_time); - s->ross_sample.send_time += (tw_now(lp) - m->fwd.sim_start_time); - s->num_recvs++; - s->ross_sample.num_recvs++; - int data = m->fwd.num_bytes; - s->syn_data += data; - s->num_bytes_recvd += data; - s->ross_sample.num_bytes_recvd += data; - num_syn_bytes_recvd += data; } /* Debugging functions, may generate unused function warning */ /*static void print_waiting_reqs(uint32_t * reqs, int count) @@ -1070,8 +1255,7 @@ static int notify_posted_wait(nw_state* s, fprintf(workload_log, "\n(%lf) APP ID %d MPI WAITALL COMPLETED AT %llu ", tw_now(lp), s->app_id, LLU(s->nw_id)); wait_completed = 1; } - - m->fwd.wait_completed = 1; + m->fwd.wait_completed = 1; //This is just the individual request handle - not the entire wait. } } } @@ -1265,18 +1449,18 @@ static void codes_exec_mpi_wait_all( } else { - /* If not, add the wait operation in the pending 'waits' list. */ - struct pending_waits* wait_op = (struct pending_waits*)malloc(sizeof(struct pending_waits)); - wait_op->count = count; - wait_op->op_type = mpi_op->op_type; - assert(count < MAX_WAIT_REQS); - - for(i = 0; i < count; i++) - wait_op->req_ids[i] = mpi_op->u.waits.req_ids[i]; - - wait_op->num_completed = num_matched; - wait_op->start_time = tw_now(lp); - s->wait_op = wait_op; + /* If not, add the wait operation in the pending 'waits' list. */ + struct pending_waits* wait_op = (struct pending_waits*)malloc(sizeof(struct pending_waits)); + wait_op->count = count; + wait_op->op_type = mpi_op->op_type; + assert(count < MAX_WAIT_REQS); + + for(i = 0; i < count; i++) + wait_op->req_ids[i] = mpi_op->u.waits.req_ids[i]; + + wait_op->num_completed = num_matched; + wait_op->start_time = tw_now(lp); + s->wait_op = wait_op; } return; } @@ -1428,7 +1612,7 @@ static int rm_matching_send(nw_state * ns, } static void codes_issue_next_event_rc(tw_lp * lp) { - tw_rand_reverse_unif(lp->rng); + // tw_rand_reverse_unif(lp->rng); } /* Trigger getting next event at LP */ @@ -1439,8 +1623,9 @@ static void codes_issue_next_event(tw_lp* lp) tw_stime ts; - ts = g_tw_lookahead + 0.1 + tw_rand_exponential(lp->rng, noise); - assert(ts > 0); + ts = NEAR_ZERO; +// ts = g_tw_lookahead + 0.1 + tw_rand_exponential(lp->rng, noise); +// assert(ts > 0); e = tw_event_new( lp->gid, ts, lp ); msg = (nw_message*)tw_event_data(e); @@ -1462,14 +1647,17 @@ static void codes_exec_comp_delay( s->compute_time += (mpi_op->u.delay.nsecs/compute_time_speedup); s->ross_sample.compute_time += (mpi_op->u.delay.nsecs/compute_time_speedup); ts = (mpi_op->u.delay.nsecs/compute_time_speedup); - if(ts <= g_tw_lookahead) - { - bf->c28 = 1; - ts = g_tw_lookahead + 0.1 + tw_rand_exponential(lp->rng, noise); - } + if (ts < 0) + ts = 0; + // if(ts <= g_tw_lookahead) + // { + // bf->c28 = 1; + // // ts = g_tw_lookahead + 0.1 + tw_rand_exponential(lp->rng, noise); + // ts = g_tw_lookahead; + // } //ts += g_tw_lookahead + 0.1 + tw_rand_exponential(lp->rng, noise); - assert(ts > 0); + // assert(ts > 0); e = tw_event_new( lp->gid, ts , lp ); msg = (nw_message*)tw_event_data(e); @@ -1493,8 +1681,9 @@ static void codes_exec_mpi_recv_rc( if(bf->c6) codes_issue_next_event_rc(lp); - if(m->fwd.found_match >= 0) - { + + if(m->fwd.found_match >= 0) + { ns->recv_time = m->rc.saved_recv_time; ns->ross_sample.recv_time = m->rc.saved_recv_time_sample; //int queue_count = qlist_count(&ns->arrival_queue); @@ -1525,7 +1714,7 @@ static void codes_exec_mpi_recv_rc( { update_completed_queue_rc(ns, bf, m, lp); } - } + } else if(m->fwd.found_match < 0) { struct qlist_head * ent = qlist_pop_back(&ns->pending_recvs_queue); @@ -1645,25 +1834,42 @@ static void codes_exec_mpi_send(nw_state* s, bf->c1 = 0; bf->c4 = 0; + /* Class names in the CODES dragonfly-dally (as at 2020/09/21 - KB): + * "high" <- highest priority + * "medium" + * "low" + * "class3" + * "class4" + * "class5" + * + * The name of the first three classes are kept for backwards compatibility. TODO: Rename classes + */ char prio[12]; - if(priority_type == 0) - { - if(s->app_id == 0) - strcpy(prio, "high"); - else - strcpy(prio, "medium"); - } - else if(priority_type == 1) + switch(s->qos_level){ + case 0: + strcpy(prio, "high"); break; + case 1: + strcpy(prio, "medium"); break; + case 2: + strcpy(prio, "low"); break; + case 3: + strcpy(prio, "class3"); break; + case 4: + strcpy(prio, "class4"); break; + case 5: + strcpy(prio, "class5"); break; + default: + tw_error(TW_LOC, "\n Invalid QoS level: %d", s->qos_level); + break; + } + + if(prioritize_collectives == 1) { if(mpi_op->u.send.tag == COL_TAG || mpi_op->u.send.tag == BAR_TAG) { strcpy(prio, "high"); } - else - strcpy(prio, "medium"); } - else - tw_error(TW_LOC, "\n Invalid priority type %d", priority_type); int is_eager = 0; /* model-net event */ @@ -1731,6 +1937,7 @@ static void codes_exec_mpi_send(nw_state* s, remote_m = local_m; remote_m.msg_type = MPI_SEND_ARRIVED; + remote_m.fwd.app_id = s->app_id; m->event_rc = model_net_event_mctx(net_id, &mapping_context, &mapping_context, prio, dest_rank, mpi_op->u.send.num_bytes, (self_overhead + copy_overhead + soft_delay_mpi + nic_delay), sizeof(nw_message), (const void*)&remote_m, sizeof(nw_message), (const void*)&local_m, lp); @@ -1765,7 +1972,8 @@ static void codes_exec_mpi_send(nw_state* s, local_m.fwd.rend_send = 1; remote_m = local_m; remote_m.msg_type = MPI_REND_ARRIVED; - + + m->event_rc = model_net_event_mctx(net_id, &mapping_context, &mapping_context, prio, dest_rank, mpi_op->u.send.num_bytes, (self_overhead + soft_delay_mpi + nic_delay), sizeof(nw_message), (const void*)&remote_m, sizeof(nw_message), (const void*)&local_m, lp); @@ -1840,10 +2048,11 @@ static void update_completed_queue(nw_state* s, bf->c31 = 0; m->fwd.num_matched = 0; - int waiting = 0; - waiting = notify_posted_wait(s, bf, m, lp, req_id); + //done waiting means that this was either the only wait in the op or the last wait in the collective op. + int done_waiting = 0; + done_waiting = notify_posted_wait(s, bf, m, lp, req_id); - if(!waiting) + if(!done_waiting) { bf->c30 = 1; completed_requests * req = (completed_requests*)malloc(sizeof(completed_requests)); @@ -1905,25 +2114,33 @@ static void send_ack_back(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * lp, m remote_m.fwd.req_id = mpi_op->req_id; remote_m.fwd.matched_req = matched_req; + // TODO: If we want ack messages to be in the low-latency class, change this function. -Kevin Brown 2021.02.18 char prio[12]; - if(priority_type == 0) - { - if(s->app_id == 0) - strcpy(prio, "high"); - else if(s->app_id == 1) - strcpy(prio, "medium"); - } - else if(priority_type == 1) + switch(s->qos_level){ + case 0: + strcpy(prio, "high"); break; + case 1: + strcpy(prio, "medium"); break; + case 2: + strcpy(prio, "low"); break; + case 3: + strcpy(prio, "class3"); break; + case 4: + strcpy(prio, "class4"); break; + case 5: + strcpy(prio, "class5"); break; + default: + tw_error(TW_LOC, "\n Invalid QoS level: %d", s->qos_level); + break; + } + + if(prioritize_collectives == 1) { if(mpi_op->tag == COL_TAG || mpi_op->tag == BAR_TAG) { strcpy(prio, "high"); } - else - strcpy(prio, "medium"); } - else - tw_error(TW_LOC, "\n Invalid app id"); m->event_rc = model_net_event_mctx(net_id, &mapping_context, &mapping_context, prio, dest_rank, CONTROL_MSG_SZ, (self_overhead + soft_delay_mpi + nic_delay), @@ -1939,8 +2156,8 @@ static void update_arrival_queue_rc(nw_state* s, s->ross_sample.num_bytes_recvd -= m->fwd.num_bytes; num_bytes_recvd -= m->fwd.num_bytes; - if(bf->c1) - codes_local_latency_reverse(lp); + // if(bf->c1) + // codes_local_latency_reverse(lp); if(bf->c10) send_ack_back_rc(s, bf, m, lp); @@ -2015,8 +2232,9 @@ static void update_arrival_queue(nw_state* s, tw_bf * bf, nw_message * m, tw_lp if(m->fwd.num_bytes < EAGER_THRESHOLD) { - tw_stime ts = codes_local_latency(lp); - assert(ts > 0); + // tw_stime ts = codes_local_latency(lp); + tw_stime ts = 0; + // assert(ts > 0); bf->c1 = 1; tw_event *e_callback = tw_event_new(rank_to_lpid(global_src_id), @@ -2097,6 +2315,9 @@ void nw_test_init(nw_state* s, tw_lp* lp) s->all_reduce_time = 0; s->prev_switch = 0; s->max_time = 0; + s->qos_level = 0; //TODO: We need a more elegant solution for determining if qos is enabled or not. + // This had been -1 but if qos is not configured (single job no workload conf file) + // then this will error out char type_name[512]; @@ -2129,6 +2350,11 @@ void nw_test_init(nw_state* s, tw_lp* lp) return; } + s->num_own_job_ranks_completed = 0; + + int num_jobs = codes_jobmap_get_num_jobs(jobmap_ctx); + s->known_completed_jobs = calloc(num_jobs, sizeof(int)); + if (strcmp(workload_type, "dumpi") == 0){ dumpi_trace_params params_d; strcpy(params_d.file_name, file_name_of_job[lid.job]); @@ -2139,6 +2365,11 @@ void nw_test_init(nw_state* s, tw_lp* lp) params_d.num_net_traces = num_traces_of_job[lid.job]; params = (char*)¶ms_d; strcpy(type_name, "dumpi-trace-workload"); + + if(strlen(workloads_conf_file) > 0) + { + s->qos_level = qos_level_of_job[lid.job]; + } // printf("network LP nw id %d app id %d local rank %d generating events, lp gid is %ld \n", s->nw_id, // s->app_id, s->local_rank, lp->gid); #ifdef ENABLE_CORTEX_PYTHON @@ -2157,8 +2388,29 @@ void nw_test_init(nw_state* s, tw_lp* lp) } else if(strlen(workloads_conf_file) > 0) { - strcpy(oc_params.workload_name, file_name_of_job[lid.job]); - + short filename_supplied = 0; + int len = strlen(file_name_of_job[lid.job]); + if (len > 4) { + char *last_five = &file_name_of_job[lid.job][len-5]; + if (strcmp(".json", last_five) == 0) + { + filename_supplied = 1; + } + } + if (filename_supplied) { //then we were supplied a filepath + strcpy(oc_params.file_path, file_name_of_job[lid.job]); + oc_params.workload_name[0] = '\0'; + if(lid.rank == 0) + printf("Workload Filepath provided: %s\n", oc_params.file_path); + } + else { //then we were supplied just the name of the workload and will use on of the defaults + strcpy(oc_params.workload_name, file_name_of_job[lid.job]); + oc_params.file_path[0] = '\0'; + if(lid.rank == 0) + printf("Workload name provided: %s\n",oc_params.workload_name); + } + + s->qos_level = qos_level_of_job[lid.job]; } //assert(strcmp(oc_params.workload_name, "lammps") == 0 || strcmp(oc_params.workload_name, "nekbone") == 0); @@ -2212,7 +2464,7 @@ void nw_test_init(nw_state* s, tw_lp* lp) if(strncmp(file_name_of_job[lid.job], "synthetic", 9) == 0) { sscanf(file_name_of_job[lid.job], "synthetic%d", &synthetic_pattern); - if(synthetic_pattern <=0 || synthetic_pattern > 5) + if(synthetic_pattern <=0 || synthetic_pattern > 6) { printf("\n Undefined synthetic pattern: setting to uniform random "); s->synthetic_pattern = 1; @@ -2221,16 +2473,32 @@ void nw_test_init(nw_state* s, tw_lp* lp) { s->synthetic_pattern = synthetic_pattern; } + s->qos_level = qos_level_of_job[lid.job]; tw_event * e; nw_message * m_new; - tw_stime ts = tw_rand_exponential(lp->rng, noise); + // tw_stime ts = tw_rand_exponential(lp->rng, noise); + tw_stime ts = 0; e = tw_event_new(lp->gid, ts, lp); m_new = (nw_message*)tw_event_data(e); m_new->msg_type = CLI_BCKGND_GEN; tw_event_send(e); is_synthetic = 1; + if(lid.rank == 0){ + for(int k = 0; k < period_count[lid.job]; k++){ + tw_event * e2; + nw_message * m_new2; + tw_stime ts2 = period_time[lid.job][k]; + e2 = tw_event_new(lp->gid, ts2, lp); + m_new2 = (nw_message*)tw_event_data(e2); + m_new2->msg_type = CLI_BCKGND_CHANGE; + m_new2->fwd.msg_send_time = period_interval[lid.job][k]; + m_new2->rc.saved_send_time = mean_interval_of_job[s->app_id]; + tw_event_send(e2); + } + } + } else { @@ -2287,7 +2555,8 @@ void nw_test_event_handler(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * lp) tw_event *e_callback = tw_event_new(rank_to_lpid(global_src_id), - codes_local_latency(lp), lp); + 0, lp); + // codes_local_latency(lp), lp); nw_message *m_callback = (nw_message*)tw_event_data(e_callback); m_callback->msg_type = MPI_SEND_ARRIVED_CB; m_callback->fwd.msg_send_time = tw_now(lp) - m->fwd.sim_start_time; @@ -2364,18 +2633,26 @@ void nw_test_event_handler(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * lp) gen_synthetic_tr(s, bf, m, lp); break; + case CLI_BCKGND_CHANGE: + mean_interval_of_job[s->app_id] = m->fwd.msg_send_time; + printf("======== CHANGE [now: %lf] App:%d | Interval: %f\n", tw_now(lp), s->app_id, mean_interval_of_job[s->app_id]); + break; + case CLI_BCKGND_ARRIVE: arrive_syn_tr(s, bf, m, lp); break; case CLI_NBR_FINISH: - finish_nbr_wkld(s, bf, m, lp); + handle_neighbor_finish(s, lp, bf, m); break; case CLI_BCKGND_FIN: finish_bckgnd_traffic(s, bf, m, lp); break; + case CLI_OTHER_FINISH: + handle_other_finish(s, lp, bf, m); + break; } } @@ -2393,7 +2670,7 @@ static void get_next_mpi_operation_rc(nw_state* s, tw_bf * bf, nw_message * m, t if(bf->c19) return; - notify_neighbor_rc(s, lp, bf, m); + notify_root_rank_rc(s, lp, bf, m); return; } switch(m->op_type) @@ -2422,8 +2699,8 @@ static void get_next_mpi_operation_rc(nw_state* s, tw_bf * bf, nw_message * m, t codes_issue_next_event_rc(lp); else { - if (bf->c28) - tw_rand_reverse_unif(lp->rng); + // if (bf->c28) + // tw_rand_reverse_unif(lp->rng); s->compute_time = m->rc.saved_delay; s->ross_sample.compute_time = m->rc.saved_delay_sample; } @@ -2477,9 +2754,14 @@ static void get_next_mpi_operation_rc(nw_state* s, tw_bf * bf, nw_message * m, t codes_exec_mpi_wait_all_rc(s, bf, m, lp); } break; + case CODES_WK_MARK: + codes_issue_next_event_rc(lp); + break; + default: printf("\n Invalid op type %d ", m->op_type); } + free(m->mpi_op); } static void get_next_mpi_operation(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * lp) @@ -2488,18 +2770,16 @@ static void get_next_mpi_operation(nw_state* s, tw_bf * bf, nw_message * m, tw_l // printf("\n App id %d local rank %d ", s->app_id, s->local_rank); // struct codes_workload_op mpi_op; // codes_workload_get_next(wrkld_id, s->app_id, s->local_rank, &mpi_op); - struct codes_workload_op * mpi_op = (struct codes_workload_op*)malloc(sizeof(struct codes_workload_op)); codes_workload_get_next(wrkld_id, s->app_id, s->local_rank, mpi_op); m->mpi_op = mpi_op; m->op_type = mpi_op->op_type; - + if(mpi_op->op_type == CODES_WK_END) { s->elapsed_time = tw_now(lp) - s->start_time; s->is_finished = 1; - if(!alloc_spec) { bf->c9 = 1; @@ -2508,17 +2788,11 @@ static void get_next_mpi_operation(nw_state* s, tw_bf * bf, nw_message * m, tw_l /* Notify ranks from other job that checkpoint traffic has * completed */ - printf("\n Network node %d Rank %llu finished at %lf ", s->local_rank, LLU(s->nw_id), tw_now(lp)); + printf("\n Network node %d Rank %llu App %d finished at %lf ", s->local_rank, LLU(s->nw_id), s->app_id, tw_now(lp)); int num_jobs = codes_jobmap_get_num_jobs(jobmap_ctx); - if(num_jobs <= 1 || is_synthetic == 0) - { - bf->c19 = 1; - return; - } - if(num_qos_levels == 1) //notify neighbor isn't really compatible with QoS, so notify_neighbor is only called if num_qos_levels == 1 (QoS off) - notify_neighbor(s, lp, bf, m); -// printf("Client rank %llu completed workload, local rank %d .\n", s->nw_id, s->local_rank); + notify_root_rank(s, lp, bf, m); + // printf("Client rank %llu completed workload, local rank %d .\n", s->nw_id, s->local_rank); return; } @@ -2585,7 +2859,7 @@ static void get_next_mpi_operation(nw_state* s, tw_bf * bf, nw_message * m, tw_l { bf->c27 = 1; m->rc.saved_delay = s->all_reduce_time; - s->all_reduce_time += (tw_now(lp) - s->col_time); + s->all_reduce_time += tw_now(lp) - s->col_time; m->rc.saved_send_time = s->col_time; s->col_time = 0; s->num_all_reduce++; @@ -2610,6 +2884,16 @@ static void get_next_mpi_operation(nw_state* s, tw_bf * bf, nw_message * m, tw_l codes_issue_next_event(lp); } break; + + case CODES_WK_MARK: + { + printf("\n MARK_%d node %llu job %d rank %d time %lf ", mpi_op->u.send.tag, LLU(s->nw_id), s->app_id, s->local_rank, tw_now(lp)); + m->rc.saved_marker_time = tw_now(lp); + codes_issue_next_event(lp); + } + break; + + default: printf("\n Invalid op type %d ", mpi_op->op_type); } @@ -2689,8 +2973,13 @@ void nw_test_finalize(nw_state* s, tw_lp* lp) s->num_bytes_recvd, s->send_time, s->elapsed_time - s->compute_time, s->compute_time, avg_msg_time, s->max_time); lp_io_write(lp->gid, (char*)"mpi-replay-stats", written, s->output_buf); - if(s->elapsed_time - s->compute_time > max_comm_time) - max_comm_time = s->elapsed_time - s->compute_time; + tw_stime my_comm_time = s->elapsed_time - s->compute_time; + + if(my_comm_time > max_comm_time) + max_comm_time = my_comm_time; + + if(s->elapsed_time > max_elapsed_time_per_job[s->app_id]) + max_elapsed_time_per_job[s->app_id] = s->elapsed_time; if(s->elapsed_time > max_time ) max_time = s->elapsed_time; @@ -2764,8 +3053,6 @@ void nw_test_event_handler_rc(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * l case MPI_REND_ARRIVED: { - codes_local_latency_reverse(lp); - if(bf->c10) codes_issue_next_event_rc(lp); @@ -2785,20 +3072,55 @@ void nw_test_event_handler_rc(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * l gen_synthetic_tr_rc(s, bf, m, lp); break; + case CLI_BCKGND_CHANGE: + mean_interval_of_job[s->app_id] = m->rc.saved_send_time; + break; + case CLI_BCKGND_ARRIVE: arrive_syn_tr_rc(s, bf, m, lp); break; case CLI_NBR_FINISH: - finish_nbr_wkld_rc(s, bf, m, lp); + handle_neighbor_finish_rc(s, lp, bf, m); break; case CLI_BCKGND_FIN: finish_bckgnd_traffic_rc(s, bf, m, lp); break; + + case CLI_OTHER_FINISH: + handle_other_finish_rc(s, lp, bf, m); + break; } } +void nw_test_event_handler_commit(nw_state* s, tw_bf * bf, nw_message * m, tw_lp * lp) +{ + switch(m->msg_type) + { + case MPI_OP_GET_NEXT: + if (m->mpi_op->op_type == CODES_WK_MARK) { + if (OUTPUT_MARKS) + { + int written1; + char marker_filename[128]; + written1 = sprintf(marker_filename, "mpi-replay-marker-tag-times"); + marker_filename[written1] = '\0'; + + char tag_line[32]; + int written; + written = sprintf(tag_line, "%d %d %.5f\n",s->nw_id, m->mpi_op->u.send.tag, m->rc.saved_marker_time); + lp_io_write(lp->gid, marker_filename, written, tag_line); + } + } + + + + free(m->mpi_op); + break; + } +} + const tw_optdef app_opt [] = { TWOPT_GROUP("Network workload test"), @@ -2807,8 +3129,11 @@ const tw_optdef app_opt [] = TWOPT_CHAR("workload_file", workload_file, "workload file name"), TWOPT_CHAR("alloc_file", alloc_file, "allocation file name"), TWOPT_CHAR("workload_conf_file", workloads_conf_file, "workload config file name"), + TWOPT_CHAR("link_failure_file", g_nm_link_failure_filepath, "filepath for override of link failure file from configuration for supporting models"), + TWOPT_CHAR("workload_timer_file", workloads_timer_file, "workload timer file name (for starting/pausing/stopping synthetic traffic)"), + TWOPT_CHAR("workload_period_file", workloads_period_file, "workload periods file name (for changing the per-job synthetic traffic load at specified periods/times)"), TWOPT_UINT("num_net_traces", num_net_traces, "number of network traces"), - TWOPT_UINT("priority_type", priority_type, "Priority type (zero): high priority to foreground traffic and low to background/2nd job, (one): high priority to collective operations "), + TWOPT_UINT("priority_type", prioritize_collectives, "Priority type (zero): Normal, (one): high priority to collective operations "), TWOPT_UINT("payload_sz", payload_sz, "size of payload for synthetic traffic "), TWOPT_ULONGLONG("max_gen_data", max_gen_data, "maximum data to be generated for synthetic traffic (Default 0 (OFF))"), TWOPT_UINT("eager_threshold", EAGER_THRESHOLD, "the transition point for eager/rendezvous protocols (Default 8192)"), @@ -2839,7 +3164,7 @@ tw_lptype nw_lp = { (pre_run_f) NULL, (event_f) nw_test_event_handler, (revent_f) nw_test_event_handler_rc, - (commit_f) NULL, + (commit_f) nw_test_event_handler_commit, (final_f) nw_test_finalize, (map_f) codes_mapping, sizeof(nw_state) @@ -2967,6 +3292,7 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) workload_type[0]='\0'; tw_opt_add(app_opt); + tw_opt_add(cc_app_opt); tw_init(argc, argv); #ifdef USE_RDAMARIS if(g_st_ross_rank) @@ -2980,6 +3306,8 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) printf("Usage: mpirun -np n ./modelnet-mpi-replay --sync=1/3" " --workload_type=dumpi/online" " --workload_conf_file=prefix-workload-file-name" + " --workload_timer_file=timer-file" + " --workload_period_file=period-file" " --alloc_file=alloc-file-name" #ifdef ENABLE_CORTEX_PYTHON " --cortex-file=cortex-file-name" @@ -2995,11 +3323,15 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) jobmap_ctx = NULL; // make sure it's NULL if it's not used - sprintf(sampling_dir, "sampling-dir"); - mkdir(sampling_dir, S_IRUSR | S_IWUSR | S_IXUSR); - sprintf(mpi_msg_dir, "synthetic%d", syn_type); - mkdir(mpi_msg_dir, S_IRUSR | S_IWUSR | S_IXUSR); + + if(enable_msg_tracking) { + sprintf(sampling_dir, "sampling-dir"); + mkdir(sampling_dir, S_IRUSR | S_IWUSR | S_IXUSR); + + sprintf(mpi_msg_dir, "synthetic%d", syn_type); + mkdir(mpi_msg_dir, S_IRUSR | S_IWUSR | S_IXUSR); + } if(strlen(workloads_conf_file) > 0) { FILE *name_file = fopen(workloads_conf_file, "r"); @@ -3010,30 +3342,78 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) char ref = '\n'; while(!feof(name_file)) { - ref = fscanf(name_file, "%d %s", &num_traces_of_job[i], file_name_of_job[i]); + //TODO: can we allow for a 2 item line but with defaults for the last two? + ref = fscanf(name_file, "%d %s %d %f", &num_traces_of_job[i], file_name_of_job[i], &qos_level_of_job[i], &mean_interval_of_job[i]); if(ref != EOF && strncmp(file_name_of_job[i], "synthetic", 9) == 0) { num_syn_clients = num_traces_of_job[i]; num_net_traces += num_traces_of_job[i]; + is_job_synthetic[i] = 1; is_synthetic = 1; + num_total_jobs += 1; + // Make sure BISECTION job has even number of clients + if (strcmp(file_name_of_job[i], "synthetic6") == 0 && num_traces_of_job[i] % 2 != 0) + tw_error(TW_LOC, "BISECTION requires and even number of nodes."); + } else if(ref!=EOF) { if(enable_debug) - printf("\n%d traces of app %s \n", num_traces_of_job[i], file_name_of_job[i]); + printf("\n%d traces of app %s (default qos class: %d)\n", num_traces_of_job[i], file_name_of_job[i], qos_level_of_job[i]); num_net_traces += num_traces_of_job[i]; num_dumpi_traces += num_traces_of_job[i]; + is_job_synthetic[i] = 0; + num_nonsyn_jobs += 1; + num_total_jobs += 1; } i++; } - printf("\n num_net_traces %d ", num_net_traces); + printf("\n num_net_traces %d; num_dumpi_traces %d", num_net_traces, num_dumpi_traces); fclose(name_file); assert(strlen(alloc_file) != 0); alloc_spec = 1; jobmap_p.alloc_file = alloc_file; jobmap_ctx = codes_jobmap_configure(CODES_JOBMAP_LIST, &jobmap_p); + + + if(strlen(workloads_timer_file) > 0){ + FILE *timer_file = fopen(workloads_timer_file, "r"); + if(!timer_file) + tw_error(TW_LOC, "\n Could not open file %s ", workloads_timer_file); + + int j = 0; + char ref2 = '\n'; + while(!feof(timer_file)) + { + ref2 = fscanf(timer_file, "%ld %ld", &job_timer1[j], &job_timer2[j]); + j++; + } + fclose(timer_file); + } + + if(strlen(workloads_period_file) > 0){ + FILE *period_file = fopen(workloads_period_file, "r"); + if(!period_file) + tw_error(TW_LOC, "\n Could not open file %s ", workloads_period_file); + + int j = 0; + char ref2 = '\n'; + while(!feof(period_file)) + { + ref2 = fscanf(period_file, "%d", &period_count[j]); + if(ref2 != EOF){ + printf("======== [ID: %d] Period count: %d\n", j, period_count[j]); + for(int k = 0; k < period_count[j]; k++){ + fscanf(period_file, "%ld:%f", &period_time[j][k], &period_interval[j][k]); + printf("======== [ID: %d] Period time and interval: %ld and %f\n", j, period_time[j][k], period_interval[j][k]); + } + } + j++; + } + fclose(period_file); + } } else { @@ -3051,6 +3431,14 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) jobmap_ctx = codes_jobmap_configure(CODES_JOBMAP_LIST, &jobmap_p); } } + + if (jobmap_ctx == NULL) //then we need to set up an identity jobmap for the ranks that do exist + { + jobmap_ident_p.num_ranks = num_net_traces; + jobmap_ctx = codes_jobmap_configure(CODES_JOBMAP_IDENTITY, &jobmap_ident_p); + } + + MPI_Comm_rank(MPI_COMM_CODES, &rank); MPI_Comm_size(MPI_COMM_CODES, &nprocs); @@ -3135,6 +3523,7 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) model_net_enable_sampling(sampling_interval, sampling_end_time); codes_mapping_setup(); + congestion_control_set_jobmap(jobmap_ctx, net_id); //must be placed after codes_mapping_setup - where g_congestion_control_enabled is set num_mpi_lps = codes_mapping_get_lp_count("MODELNET_GRP", 0, "nw-lp", NULL, 0); @@ -3195,6 +3584,14 @@ int modelnet_mpi_replay(MPI_Comm comm, int* argc, char*** argv ) total_max_recv_time, total_avg_recv_time/num_net_traces, total_max_wait_time, total_avg_wait_time/num_net_traces); + printf("\n----------\n"); + printf("Per App Max Elapsed Times:\n"); + for(int i = 0; i < num_total_jobs; i++) + { + printf("\tApp %d: %.4f\n",i,max_elapsed_time_per_job[i]); + } + printf("----------\n"); + if(synthetic_pattern == PERMUTATION) printf("\n Threshold for random permutation %ld ", perm_switch_thresh); } diff --git a/src/network-workloads/model-net-synthetic-dragonfly-all.c b/src/network-workloads/model-net-synthetic-dragonfly-all.c index e9a46e1d..b763accc 100644 --- a/src/network-workloads/model-net-synthetic-dragonfly-all.c +++ b/src/network-workloads/model-net-synthetic-dragonfly-all.c @@ -9,12 +9,22 @@ #include "codes/codes_mapping.h" #include "codes/configuration.h" #include "codes/lp-type-lookup.h" +#include "codes/congestion-controller-core.h" +#include +#define G_TW_END_OPT_OVERRIDE 1 static int net_id = 0; static int traffic = 1; -static double arrival_time = 1000.0; +static double warm_up_time = 0.0; +static double arrival_time = 0.0; +static double load = 0.0; static int PAYLOAD_SZ = 2048; +static double mean_interval = 0.0; +static double link_bandwidth = 0.0; + +static double pe_total_offered_load, pe_total_observed_load = 0.0; +static double pe_max_end_ts = 0.0; static int num_servers_per_rep = 0; static int num_routers_per_grp = 0; @@ -22,6 +32,9 @@ static int num_nodes_per_grp = 0; static int num_nodes_per_router = 0; static int num_groups = 0; static unsigned long long num_nodes = 0; +static int total_terminals = 0; +static int num_servers = 0; +static int num_servers_per_terminal = 0; //Dragonfly Custom Specific values int num_router_rows, num_router_cols; @@ -39,6 +52,7 @@ static int do_lp_io = 0; static int num_msgs = 20; static tw_stime sampling_interval = 800000; static tw_stime sampling_end_time = 1600000; +static long long rperm_threshold = 131072; typedef struct svr_msg svr_msg; typedef struct svr_state svr_state; @@ -59,7 +73,8 @@ enum svr_event { KICKOFF, /* kickoff event */ REMOTE, /* remote event */ - LOCAL /* local event */ + LOCAL, /* local event */ + ACK /*pdes acknowledgement of received message*/ }; /* type of synthetic traffic */ @@ -76,12 +91,17 @@ enum TRAFFIC struct svr_state { int msg_sent_count; /* requests sent */ + int warm_msg_sent_count; int msg_recvd_count; /* requests recvd */ int local_recvd_count; /* number of local messages received */ tw_stime start_ts; /* time that we started sending requests */ - tw_stime end_ts; /* time that we ended sending requests */ + tw_stime last_send_ts; + tw_stime first_recv_ts; + tw_stime last_recv_ts; /* time that we ended sending requests */ int svr_id; int dest_id; + long long rperm_data; /* amount of data sent this rperm period */ + int msg_complete_count; //number of messages that successfully made it to their dest svr tw_stime max_server_latency; /* maximum measured packet latency observed by server */ tw_stime sum_server_latency; /* running sum of measured latencies observed by server for calc of mean */ @@ -92,8 +112,12 @@ struct svr_msg enum svr_event svr_event_type; tw_lpid src; /* source of this request or ack */ tw_stime msg_start_time; + int saved_dest; /* helper for reverse computation */ int completed_sends; /* helper for reverse computation */ tw_stime saved_time; /* helper for reverse computation */ + long long saved_rperm_data; /* helper for reverse computation */ + tw_stime saved_end_time; + tw_stime saved_max_end_time; model_net_event_return event_rc; }; @@ -172,11 +196,15 @@ const tw_optdef app_opt [] = TWOPT_UINT("traffic", traffic, "UNIFORM RANDOM=1, NEAREST NEIGHBOR=2 "), TWOPT_UINT("num_messages", num_msgs, "Number of messages to be generated per terminal "), TWOPT_UINT("payload_sz",PAYLOAD_SZ, "size of the message being sent "), + TWOPT_UINT("rperm_threshold",rperm_threshold, "size of rperm data sent before selecting new dest "), TWOPT_STIME("sampling-interval", sampling_interval, "the sampling interval "), TWOPT_STIME("sampling-end-time", sampling_end_time, "sampling end time "), TWOPT_STIME("arrival_time", arrival_time, "INTER-ARRIVAL TIME"), + TWOPT_STIME("warm_up_time", warm_up_time, "Time delay before starting stats colleciton. For generating accurate observed bandwidth calculations"), + TWOPT_STIME("load_per_svr", load, "percentage of packet inter-arrival rate to simulate per server"), TWOPT_CHAR("lp-io-dir", lp_io_dir, "Where to place io output (unspecified -> no output"), TWOPT_UINT("lp-io-use-suffix", lp_io_use_suffix, "Whether to append uniq suffix to lp-io directory (default 0)"), + TWOPT_CHAR("link_failure_file", g_nm_link_failure_filepath, "filepath for override of link failure file from configuration for supporting models"), TWOPT_END() }; @@ -190,39 +218,114 @@ static void svr_add_lp_type() lp_type_register("nw-lp", svr_get_lp_type()); } -static void issue_event( +/* convert GiB/s and bytes to ns */ +static tw_stime bytes_to_ns(uint64_t bytes, double GB_p_s) +{ + tw_stime time; + + /* bytes to GB */ + time = ((double)bytes)/(1024.0*1024.0*1024.0); + /* MB to s */ + time = time / GB_p_s; + /* s to ns */ + time = time * 1000.0 * 1000.0 * 1000.0; + + return(time); +} + +static uint64_t ns_to_bytes(tw_stime ns, double GB_p_s) +{ + uint64_t bytes; + + bytes = ((ns / (1000.0*1000.0*1000.0))*GB_p_s)*(1024.0*1024.0*1024.0); + return bytes; +} + +static double ns_to_GBps(tw_stime ns, uint64_t bytes) +{ + double GB_p_s; + GB_p_s = (bytes/(1024.0*1024.0*1024.0))/(ns/(1000.0*1000.0*1000.0)); + return GB_p_s; +} + +static tw_stime issue_event( svr_state * ns, tw_lp * lp) { (void)ns; tw_event *e; svr_msg *m; - tw_stime kickoff_time; + tw_stime time_offset; + + configuration_get_value_double(&config, "PARAMS", "cn_bandwidth", NULL, &link_bandwidth); + if(!link_bandwidth) { + link_bandwidth = 4.7; + fprintf(stderr, "Bandwidth of channels not specified, setting to %lf\n", link_bandwidth); + } + + if(mean_interval == 0.0) + { + if(arrival_time != 0.0) + { + mean_interval = arrival_time; + load = ns_to_GBps(mean_interval, PAYLOAD_SZ); + } + else if (load != 0.0) + { + mean_interval = bytes_to_ns(PAYLOAD_SZ, load*link_bandwidth); + printf("load=%.2f\n",load); + } + else + { + mean_interval = 1000.0; + load = ns_to_GBps(mean_interval, PAYLOAD_SZ); + } + } /* each server sends a dummy event to itself that will kick off the real * simulation */ /* skew each kickoff event slightly to help avoid event ties later on */ - kickoff_time = 1.1 * g_tw_lookahead + tw_rand_exponential(lp->rng, arrival_time); + // time_offset = g_tw_lookahead + tw_rand_exponential(lp->rng, mean_interval); + // time_offset = tw_rand_exponential(lp->rng, mean_interval); + time_offset = mean_interval; - e = tw_event_new(lp->gid, kickoff_time, lp); + e = tw_event_new(lp->gid, time_offset, lp); m = tw_event_data(e); m->svr_event_type = KICKOFF; tw_event_send(e); + + return time_offset; } +// static void notify_workload_complete(svr_state *ns, tw_bf *bf, tw_lp *lp) +// { +// if (g_congestion_control_enabled) { +// tw_event *e; +// congestion_control_message *m; +// tw_stime noise = tw_rand_unif(lp->rng) *.001; +// bf->c10 = 1; +// e = tw_event_new(g_cc_supervisory_controller_gid, noise, lp); +// m = tw_event_data(e); +// m->type = CC_WORKLOAD_RANK_COMPLETE; +// tw_event_send(e); +// } +// } + static void svr_init( svr_state * ns, tw_lp * lp) { - ns->start_ts = 0.0; ns->dest_id = -1; ns->svr_id = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); ns->max_server_latency = 0.0; ns->sum_server_latency = 0.0; + ns->rperm_data = 0; + ns->warm_msg_sent_count = 0; + ns->first_recv_ts = -1; - issue_event(ns, lp); + ns->start_ts = issue_event(ns, lp); return; } @@ -232,22 +335,34 @@ static void handle_kickoff_rev_event( svr_msg * m, tw_lp * lp) { - if(m->completed_sends) + if(m->completed_sends) { return; + } if(b->c1) tw_rand_reverse_unif(lp->rng); - if(b->c8) - tw_rand_reverse_unif(lp->rng); + if (traffic == RAND_PERM) { + if (b->c8) { + ns->rperm_data = m->saved_rperm_data; + tw_rand_reverse_unif(lp->rng); + ns->dest_id = m->saved_dest; + } + else { + ns->rperm_data -= PAYLOAD_SZ; + } + } if(traffic == RANDOM_OTHER_GROUP) { tw_rand_reverse_unif(lp->rng); tw_rand_reverse_unif(lp->rng); } + if(b->c5) + ns->warm_msg_sent_count--; model_net_event_rc2(lp, &m->event_rc); ns->msg_sent_count--; - tw_rand_reverse_unif(lp->rng); + // tw_rand_reverse_unif(lp->rng); + // tw_rand_reverse_unif(lp->rng); } static void handle_kickoff_event( svr_state * ns, @@ -276,7 +391,6 @@ static void handle_kickoff_event( memcpy(m_remote, m_local, sizeof(svr_msg)); m_remote->svr_event_type = REMOTE; - ns->start_ts = tw_now(lp); codes_mapping_get_lp_info(lp->gid, group_name, &group_index, lp_type_name, &lp_type_index, anno, &rep_id, &offset); int local_id = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); @@ -299,15 +413,18 @@ static void handle_kickoff_event( } else if(traffic == RAND_PERM) { - if(ns->dest_id == -1) - { + if (ns->dest_id == -1 || ns->rperm_data > rperm_threshold) { b->c8 = 1; + m->saved_dest = ns->dest_id; ns->dest_id = tw_rand_integer(lp->rng, 0, num_nodes - 1); local_dest = ns->dest_id; + m->saved_rperm_data = ns->rperm_data; + ns->rperm_data = PAYLOAD_SZ; //reset to 0 + payload size for this run } else { local_dest = ns->dest_id; + ns->rperm_data += PAYLOAD_SZ; } } else if(traffic == RANDOM_OTHER_GROUP) @@ -330,16 +447,61 @@ static void handle_kickoff_event( printf("\n LP %d sending to %llu num nodes %llu ", local_id, LLU(local_dest), num_nodes); } + + if (tw_now(lp) >= warm_up_time) { + b->c5 = 1; + ns->warm_msg_sent_count++; + } + assert(local_dest < num_nodes); // codes_mapping_get_lp_id(group_name, lp_type_name, anno, 1, local_dest / num_servers_per_rep, local_dest % num_servers_per_rep, &global_dest); global_dest = codes_mapping_get_lpid_from_relative(local_dest, group_name, lp_type_name, NULL, 0); + ns->msg_sent_count++; + ns->last_send_ts = tw_now(lp); m->event_rc = model_net_event(net_id, "test", global_dest, PAYLOAD_SZ, 0.0, sizeof(svr_msg), (const void*)m_remote, sizeof(svr_msg), (const void*)m_local, lp); - issue_event(ns, lp); return; } +static void handle_ack_event(svr_state * ns, tw_bf *bf, svr_msg *m, tw_lp *lp) +{ + ns->msg_complete_count++; + if (ns->first_recv_ts == -1) { + bf->c12 = 1; + ns->first_recv_ts = tw_now(lp); + } + // if (ns->msg_complete_count >= num_msgs) + // { + bf->c11 = 1; + + m->saved_end_time = ns->last_recv_ts; + ns->last_recv_ts = tw_now(lp); + + m->saved_max_end_time = pe_max_end_ts; + if (ns->last_recv_ts > pe_max_end_ts) + pe_max_end_ts = ns->last_recv_ts; + // } + +} + +static void handle_ack_event_rc(svr_state * ns, tw_bf *bf, svr_msg *m, tw_lp *lp) +{ + ns->msg_complete_count--; + if (bf->c12) + ns->first_recv_ts = -1; + + if (bf->c11) { + ns->last_recv_ts = m->saved_end_time; + + pe_max_end_ts = m->saved_max_end_time; + + if (bf->c10) + tw_rand_reverse_unif(lp->rng); + } + +} + static void handle_remote_rev_event( svr_state * ns, tw_bf * b, @@ -349,6 +511,10 @@ static void handle_remote_rev_event( (void)b; (void)m; (void)lp; + + if (b->c3) { + // ns->end_ts = m->saved_end_time; + ns->msg_recvd_count--; tw_stime packet_latency = tw_now(lp) - m->msg_start_time; @@ -356,6 +522,8 @@ static void handle_remote_rev_event( if (b->c2) ns->max_server_latency = m->saved_time; + // tw_rand_reverse_unif(lp->rng); + } } static void handle_remote_event( @@ -367,16 +535,32 @@ static void handle_remote_event( (void)b; (void)m; (void)lp; - ns->msg_recvd_count++; - - tw_stime packet_latency = tw_now(lp) - m->msg_start_time; - ns->sum_server_latency += packet_latency; - if (packet_latency > ns->max_server_latency) { - b->c2 = 1; - m->saved_time = ns->max_server_latency; - ns->max_server_latency = packet_latency; - } + if (tw_now(lp) >= warm_up_time) { + b->c3 = 1; + ns->msg_recvd_count++; + + tw_stime packet_latency = tw_now(lp) - m->msg_start_time; + ns->sum_server_latency += packet_latency; + if (packet_latency > ns->max_server_latency) { + b->c2 = 1; + m->saved_time = ns->max_server_latency; + ns->max_server_latency = packet_latency; + } + + // m->saved_end_time = ns->end_ts; + // ns->end_ts = tw_now(lp); + + + // tw_stime noise = tw_rand_unif(lp->rng) * .001; + + tw_event *e; + svr_msg *new_msg; + e = tw_event_new(m->src, 0, lp); + new_msg = tw_event_data(e); + new_msg->svr_event_type = ACK; + tw_event_send(e); + } } static void handle_local_rev_event( @@ -388,7 +572,8 @@ static void handle_local_rev_event( (void)b; (void)m; (void)lp; - ns->local_recvd_count--; + if (b->c4) + ns->local_recvd_count--; } static void handle_local_event( @@ -400,7 +585,10 @@ static void handle_local_event( (void)b; (void)m; (void)lp; - ns->local_recvd_count++; + if (tw_now(lp) >= warm_up_time) { + b->c4 = 1; + ns->local_recvd_count++; + } } /* convert seconds to ns */ @@ -413,8 +601,7 @@ static void svr_finalize( svr_state * ns, tw_lp * lp) { - ns->end_ts = tw_now(lp); - + tw_stime now = tw_now(lp); //add to the global running sums sum_global_server_latency += ns->sum_server_latency; sum_global_messages_received += ns->msg_recvd_count; @@ -426,9 +613,42 @@ static void svr_finalize( //this server's mean // tw_stime mean_packet_latency = ns->sum_server_latency/ns->msg_recvd_count; - //printf("server %llu recvd %d bytes in %f seconds, %f MiB/s sent_count %d recvd_count %d local_count %d \n", (unsigned long long)lp->gid, PAYLOAD_SZ*ns->msg_recvd_count, ns_to_s(ns->end_ts-ns->start_ts), // ((double)(PAYLOAD_SZ*ns->msg_sent_count)/(double)(1024*1024)/ns_to_s(ns->end_ts-ns->start_ts)), ns->msg_sent_count, ns->msg_recvd_count, ns->local_recvd_count); + + char output_buf[1024]; + + double observed_load_time = ((double)ns->last_recv_ts-warm_up_time) - ns->first_recv_ts; + double observed_load = ((double)PAYLOAD_SZ*(double)ns->msg_recvd_count)/observed_load_time; + observed_load = observed_load * (double)(1000*1000*1000); + observed_load = observed_load / (double)(1024*1024*1024); + + // double offered_load = (double)(load*link_bandwidth); + + double offered_load_time = ((double)ns->last_send_ts-warm_up_time) - ns->start_ts; + double offered_load = ((double)PAYLOAD_SZ*(double)ns->warm_msg_sent_count)/offered_load_time; + offered_load = offered_load * (double)(1000*1000*1000); + offered_load = offered_load / (double)(1024*1024*1024); + + int written = 0; + int written2 = 0; + + // printf("%.2f Offered | %.2f Observed locally\n",offered_load,observed_load); + + pe_total_offered_load+= offered_load; + pe_total_observed_load+= observed_load; + + if(lp->gid == 0){ + written = sprintf(output_buf, "# Format \n"); + } + + written += sprintf(output_buf + written, "%llu %d %d %d %d %f %f %f %f\n",LLU(lp->gid), ns->msg_sent_count, ns->msg_recvd_count, + PAYLOAD_SZ*ns->msg_sent_count, PAYLOAD_SZ*ns->msg_recvd_count, load*link_bandwidth, observed_load, ns->last_recv_ts, observed_load_time); + + lp_io_write(lp->gid, "synthetic-stats", written, output_buf); + + + return; } @@ -449,6 +669,9 @@ static void svr_rev_event( case KICKOFF: handle_kickoff_rev_event(ns, b, m, lp); break; + case ACK: + handle_ack_event_rc(ns, b, m, lp); + break; default: assert(0); break; @@ -469,9 +692,12 @@ static void svr_event( case LOCAL: handle_local_event(ns, b, m, lp); break; - case KICKOFF: - handle_kickoff_event(ns, b, m, lp); - break; + case KICKOFF: + handle_kickoff_event(ns, b, m, lp); + break; + case ACK: + handle_ack_event(ns, b, m, lp); + break; default: printf("\n Invalid message type %d ", m->svr_event_type); assert(0); @@ -484,21 +710,38 @@ static void svr_report_stats() { long long total_received_messages; tw_stime total_sum_latency, max_latency, mean_latency; - + tw_stime max_end_time; MPI_Reduce( &sum_global_messages_received, &total_received_messages, 1, MPI_LONG_LONG, MPI_SUM, 0, MPI_COMM_CODES); MPI_Reduce( &sum_global_server_latency, &total_sum_latency, 1,MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_CODES); MPI_Reduce( &max_global_server_latency, &max_latency, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_CODES); + MPI_Reduce( &pe_max_end_ts, &max_end_time, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_CODES); mean_latency = total_sum_latency / total_received_messages; if(!g_tw_mynode) { - printf("\nSynthetic Workload LP Stats: Mean Message Latency: %lf us, Maximum Message Latency: %lf us, Total Messages Received: %lld\n", + printf("\nSynthetic Workload LP Stats: Mean Message Latency: %lf us, Maximum Message Latency: %lf us, Total Messages Received: %lld\n", (float)mean_latency / 1000, (float)max_latency / 1000, total_received_messages); + printf("\tMaximum Workload End Time %.2f\n",max_end_time); } } +static void aggregate_svr_stats(int myrank) +{ + + double agg_offered_load, agg_observed_load; + MPI_Reduce(&pe_total_offered_load, &agg_offered_load, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_CODES); + MPI_Reduce(&pe_total_observed_load, &agg_observed_load, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_CODES); + + double avg_offered_load = agg_offered_load / num_servers * num_servers_per_terminal; + double avg_observed_load = agg_observed_load / num_servers * num_servers_per_terminal; + + if (myrank == 0) { + printf("\nSynthetic-All Stats ---\n"); + printf("AVG OFFERED LOAD = %.3f | AVG OBSERVED LOAD = %.3f\n",avg_offered_load, avg_observed_load); + } +} int main( int argc, @@ -544,8 +787,10 @@ int main( net_id = *net_ids; free(net_ids); - /* 5 days of simulation time */ - g_tw_ts_end = s_to_ns(5 * 24 * 60 * 60); + if(G_TW_END_OPT_OVERRIDE) { + /* 5 days of simulation time */ + g_tw_ts_end = s_to_ns(5 * 24 * 60 * 60); + } model_net_enable_sampling(sampling_interval, sampling_end_time); if(!(net_id == DRAGONFLY_DALLY || net_id == DRAGONFLY_PLUS || net_id == DRAGONFLY_CUSTOM || net_id == DRAGONFLY)) @@ -565,6 +810,7 @@ int main( configuration_get_value_int(&config, "PARAMS", "num_routers", NULL, &num_routers); configuration_get_value_int(&config, "PARAMS", "num_groups", NULL, &num_groups); configuration_get_value_int(&config, "PARAMS", "num_cns_per_router", NULL, &num_nodes_per_router); + total_terminals = codes_mapping_get_lp_count("MODELNET_GRP", 0, "modelnet_dragonfly_dally", NULL, 1); num_routers_with_cns_per_group = num_routers; } else if (net_id == DRAGONFLY_PLUS) { @@ -575,6 +821,7 @@ int main( configuration_get_value_int(&config, "PARAMS", "num_routers", NULL, &num_routers); configuration_get_value_int(&config, "PARAMS", "num_groups", NULL, &num_groups); configuration_get_value_int(&config, "PARAMS", "num_cns_per_router", NULL, &num_nodes_per_router); + total_terminals = codes_mapping_get_lp_count("MODELNET_GRP", 0, "modelnet_dragonfly_plus", NULL, 1); num_routers_with_cns_per_group = num_router_leaf; } @@ -585,6 +832,7 @@ int main( configuration_get_value_int(&config, "PARAMS", "num_router_cols", NULL, &num_router_cols); configuration_get_value_int(&config, "PARAMS", "num_groups", NULL, &num_groups); configuration_get_value_int(&config, "PARAMS", "num_cns_per_router", NULL, &num_nodes_per_router); + total_terminals = codes_mapping_get_lp_count("MODELNET_GRP", 0, "modelnet_dragonfly_custom", NULL, 1); num_routers_with_cns_per_group = num_router_rows * num_router_cols; } else if (net_id == DRAGONFLY) { @@ -596,11 +844,20 @@ int main( num_groups = num_routers * num_nodes_per_router + 1; } - num_nodes = num_groups * num_routers_with_cns_per_group * num_nodes_per_router; - num_nodes_per_grp = num_routers_with_cns_per_group * num_nodes_per_router; + num_servers = codes_mapping_get_lp_count("MODELNET_GRP", 0, "nw-lp", + NULL, 1); + num_nodes = num_servers; + num_servers_per_terminal = num_servers / total_terminals; + // num_nodes = num_groups * num_routers_with_cns_per_group * num_nodes_per_router; + num_nodes_per_grp = (num_nodes / num_groups); assert(num_nodes); + struct codes_jobmap_params_identity jobmap_ident_p; + jobmap_ident_p.num_ranks = num_servers; + struct codes_jobmap_ctx * jobmap_ctx = codes_jobmap_configure(CODES_JOBMAP_IDENTITY, &jobmap_ident_p); + // congestion_control_set_jobmap(jobmap_ctx, net_id); //must be placed after codes_mapping_setup - where g_congestion_control_enabled is set + if(lp_io_dir[0]) { do_lp_io = 1; @@ -615,6 +872,8 @@ int main( } model_net_report_stats(net_id); svr_report_stats(); + aggregate_svr_stats(rank); + #ifdef USE_RDAMARIS } // end if(g_st_ross_rank) #endif diff --git a/src/networks/model-net/core/model-net-lp.c b/src/networks/model-net/core/model-net-lp.c index 6b22bdd5..d469fa10 100644 --- a/src/networks/model-net/core/model-net-lp.c +++ b/src/networks/model-net/core/model-net-lp.c @@ -137,6 +137,15 @@ static void model_net_commit_event(model_net_base_state * ns, tw_bf *b, model_n if(ns->sub_type->commit != NULL) ns->sub_type->commit(ns->sub_state, b, sub_msg, lp); } + + if(m->h.event_type == MN_CONGESTION_EVENT) + { + void * sub_msg; + sub_msg = ((char*)m)+msg_offsets[CONGESTION_CONTROLLER]; + commit_f con_ev_commit = method_array[ns->net_id]->cc_congestion_event_commit_fn; + if(con_ev_commit != NULL) + con_ev_commit(ns->sub_state, b, sub_msg, lp); + } } /* setup for the ROSS event tracing */ @@ -408,6 +417,8 @@ void model_net_base_configure(){ offsetof(model_net_wrap_msg, msg.m_em); msg_offsets[EXPRESS_MESH_ROUTER] = offsetof(model_net_wrap_msg, msg.m_em); + msg_offsets[CONGESTION_CONTROLLER] = + offsetof(model_net_wrap_msg, msg.m_cc); // perform the configuration(s) @@ -579,6 +590,16 @@ void model_net_base_event( sub_msg = ((char*)m)+msg_offsets[ns->net_id]; ns->sub_type->event(ns->sub_state, b, sub_msg, lp); break; + case MN_BASE_END_NOTIF: ; + event_f end_ev = method_array[ns->net_id]->mn_end_notif_fn; + end_ev(ns->sub_state, b, m, lp); + break; + case MN_CONGESTION_EVENT: ; + event_f con_ev = method_array[ns->net_id]->cc_congestion_event_fn; + assert(g_congestion_control_enabled && con_ev != NULL); + sub_msg = ((char*)m)+msg_offsets[CONGESTION_CONTROLLER]; + con_ev(ns->sub_state, b, sub_msg, lp); + break; /* ... */ default: assert(!"model_net_base event type not known"); @@ -611,6 +632,16 @@ void model_net_base_event_rc( sub_msg = ((char*)m)+msg_offsets[ns->net_id]; ns->sub_type->revent(ns->sub_state, b, sub_msg, lp); break; + case MN_BASE_END_NOTIF: ; + event_f end_ev_rc = method_array[ns->net_id]->mn_end_notif_rc_fn; + end_ev_rc(ns->sub_state, b, m, lp); + break; + case MN_CONGESTION_EVENT: ; + revent_f con_ev_rc = method_array[ns->net_id]->cc_congestion_event_rc_fn; + assert(g_congestion_control_enabled && con_ev_rc != NULL); + sub_msg = ((char*)m)+msg_offsets[CONGESTION_CONTROLLER]; + con_ev_rc(ns->sub_state, b, sub_msg, lp); + break; /* ... */ default: assert(!"model_net_base event type not known"); @@ -984,6 +1015,72 @@ void * model_net_method_get_edata(int net_id, void *msg){ return (char*)msg + sizeof(model_net_wrap_msg) - msg_offsets[net_id]; } +// This is utilized by a workoad file, when a single workload rank has determined that +// all of the workload ranks have finished their respective tasks, it uses this method +// to send a notification to all model net LPs that the workloads have completed. +// This enables network models to implement features that require a heartbeat message +// that's repeated ad infinitum. If those ranks aren't notified that the workload +// ranks are completed, then the simulation will 'never' end. (it will run until g_tw_ts_end is reached) +// note: network models must explicitly implement and initialize the necessary model-net-method callback +//return number of random calls utilized by this method +int model_net_method_end_sim_broadcast( + tw_stime offset_ts, + tw_lp *sender) +{ + //get lp names of active model-net LPs + //send end sim notification to each LP that match an active model-net lp name + for (int cid = 0; cid < lpconf.num_uniq_lptypes; cid++) + { + const char* lp_name = codes_mapping_get_lp_name_by_cid(cid); + for (int n = 0; n < MAX_NETS; n++) + { + if (strcmp(lp_name, model_net_lp_config_names[n]) == 0) + { + // printf("ACTIVE TYPE FOUND: %s\n", lp_name); + for (int lid = 0; lid < codes_mapping_get_lp_count("MODELNET_GRP", 0, lp_name, NULL, 1); lid++) + { + tw_lpid lpgid = codes_mapping_get_lpid_from_relative(lid, NULL, lp_name, NULL, 0); + tw_event* e = model_net_method_end_sim_notification(lpgid, offset_ts, sender); + tw_event_send(e); + } + } + } + } + return 0; +} + +// see model_net_method_end_sim_broadcast for details on why this method is useful +tw_event* model_net_method_end_sim_notification( + tw_lpid dest_gid, + tw_stime offset_ts, + tw_lp *sender) +{ + tw_event *e = tw_event_new(dest_gid, offset_ts, sender); + model_net_wrap_msg *m_wrap = tw_event_data(e); + msg_set_header(model_net_base_magic, MN_BASE_END_NOTIF, sender->gid, + &m_wrap->h); + return e; +} + +tw_event* model_net_method_congestion_event(tw_lpid dest_gid, + tw_stime offset_ts, + tw_lp *sender, + void **msg_data, + void **extra_data) +{ + tw_event *e = tw_event_new(dest_gid, offset_ts, sender); + model_net_wrap_msg *m_wrap = tw_event_data(e); + msg_set_header(model_net_base_magic, MN_CONGESTION_EVENT, sender->gid, + &m_wrap->h); + *msg_data = ((char*)m_wrap)+msg_offsets[CONGESTION_CONTROLLER]; + // extra_data is optional + if (extra_data != NULL){ + *extra_data = m_wrap + 1; + } + return e; + +} + /* * Local variables: * c-indent-level: 4 diff --git a/src/networks/model-net/core/model-net.c b/src/networks/model-net/core/model-net.c index 99baf2b5..5ee14979 100644 --- a/src/networks/model-net/core/model-net.c +++ b/src/networks/model-net/core/model-net.c @@ -36,6 +36,8 @@ extern struct model_net_method loggp_method; extern struct model_net_method express_mesh_method; extern struct model_net_method express_mesh_router_method; +char g_nm_link_failure_filepath[MAX_NAME_LENGTH]; + #define X(a,b,c,d) b, char * model_net_lp_config_names[] = { NETWORK_DEF @@ -66,6 +68,7 @@ static tw_stime start_time_param; // MN_MSG_PARAM_START_TIME static double cn_bandwidth = 20; tw_stime codes_cn_delay; static int codes_node_eager_limit = 16000; +static int codes_noop_bypass = 0; // global listing of lp types found by model_net_register // - needs to be held between the register and configure calls @@ -165,6 +168,12 @@ int* model_net_configure(int *id_count){ "setting to %d\n", codes_node_eager_limit); } + ret = configuration_get_value_int(&config, "PARAMS", "codes_noop_bypass",NULL, + &codes_noop_bypass); + if(!ret && !g_tw_mynode) { + printf("CODES No-op method bypass enabled\n"); + } + return ids; } @@ -331,7 +340,7 @@ static model_net_event_return model_net_event_impl_base( tw_lpid dest_mn_lp = model_net_find_local_device_mctx(net_id, recv_map_ctx, final_dest_lp); - if ( src_mn_lp == dest_mn_lp && message_size < (uint64_t)codes_node_eager_limit) + if ( src_mn_lp == dest_mn_lp && message_size < (uint64_t)codes_node_eager_limit && !codes_noop_bypass) { return model_net_noop_event(final_dest_lp, is_pull, offset, message_size, remote_event_size, remote_event, self_event_size, self_event, @@ -374,6 +383,13 @@ static model_net_event_return model_net_event_impl_base( else r->msg_start_time = tw_now(sender); + if (congestion_control_is_jobmap_set()) { //perhaps make jobmap a global set regardless of congestion control + struct codes_jobmap_ctx *ctx; + ctx = congestion_control_get_jobmap(); + struct codes_jobmap_id jid; + jid = codes_jobmap_to_local_id(codes_mapping_get_lp_relative_id(sender->gid, 0, 0), ctx); + r->app_id = jid.job; + } // this is an outgoing message m->msg.m_base.is_from_remote = 0; m->msg.m_base.isQueueReq = 1; diff --git a/src/networks/model-net/dragonfly-dally.C b/src/networks/model-net/dragonfly-dally.C index 45dc400f..a45c48d3 100644 --- a/src/networks/model-net/dragonfly-dally.C +++ b/src/networks/model-net/dragonfly-dally.C @@ -29,8 +29,10 @@ #include #include #include +#include -#include "codes/connection-manager.h" +#include "codes/network-manager/dragonfly-network-manager.h" +#include "codes/congestion-controller-model.h" #ifdef ENABLE_CORTEX #include @@ -48,11 +50,19 @@ #define TRACK_PKT -1 #define TRACK_MSG -1 #define DEBUG 0 +#define DEBUG_QOS 1 #define MAX_STATS 65536 #define SHOW_ADAP_STATS 1 // maximum number of characters allowed to represent the routing algorithm as a string #define MAX_ROUTING_CHARS 32 +#define ROUTER_BW_LOG 0 + +#define OUTPUT_END_END_LATENCIES 0 +#define OUTPUT_PORT_PORT_LATENCIES 0 +#define OUTPUT_LATENCY_MODULO 1 + +#define ADD_NOISE 0 //Routing Defines //NONMIN_INCLUDE_SOURCE_DEST: Do we allow source and destination groups to be viable choces for indirect group (i.e. do we allow nonminimal routing to sometimes be minimal?) @@ -69,12 +79,23 @@ static int max_lvc_intm_g = 3; static int min_gvc_src_g = 0; static int min_gvc_intm_g = 1; -static tw_stime max_qos_monitor = 5000000000; +static int max_hops_per_group = 1; +static int max_global_hops_nonminimal = 2; +static int max_global_hops_minimal = 1; + static long num_local_packets_sr = 0; static long num_local_packets_sg = 0; static long num_remote_packets = 0; +static long global_stalled_chunk_counter = 0; + +#define OUTPUT_SNAPSHOT 0 +const static int num_snapshots = 0; +tw_stime snapshot_times[num_snapshots] = {}; +char snapshot_filename[128]; + /* time in nanosecs */ +//static int bw_reset_window = 50000000; static int bw_reset_window = 5000000; #define indexer3d(_ptr, _x, _y, _z, _maxx, _maxy, _maxz) \ @@ -88,7 +109,7 @@ using namespace std; /*MM: Maintains a list of routers connecting the source and destination groups */ static vector< vector< vector > > connectionList; -static vector< ConnectionManager > connManagerList; +static DragonflyNetworkManager netMan; /* Note: Dragonfly Dally doesn't distinguish intra links into colored "types". So the type field here is ignored. This will be changed at some point in the @@ -183,6 +204,9 @@ struct dragonfly_param { // configuration parameters int num_routers; /*Number of routers in a group*/ + int num_injection_queues; + int num_rails; /* Number of rails connecting a single terminal to the network */ + int num_planes; /* Number of router planes in the network */ double local_bandwidth;/* bandwidth of the router-router channels within a group */ double global_bandwidth;/* bandwidth of the inter-group router connections */ double cn_bandwidth;/* bandwidth of the compute node channels connected to routers */ @@ -193,10 +217,17 @@ struct dragonfly_param int chunk_size; /* full-sized packets are broken into smaller chunks.*/ int global_k_picks; /* k number of connections to select from when doing local adaptive routing */ int adaptive_threshold; + int rail_select; // method by which rails are selected + int num_parallel_switch_conns; // derived parameters + int num_rails_per_plane; + int num_routers_per_plane; int num_cn; + int cn_radix; int intra_grp_radix; + int global_radix; int num_groups; + int total_groups; int radix; int total_routers; int total_terminals; @@ -241,7 +272,7 @@ struct dfly_cn_sample long data_size_sample; double fin_hops_sample; tw_stime fin_chunks_time; - tw_stime busy_time_sample; + tw_stime* busy_time_sample; tw_stime end_time; long fwd_events; long rev_events; @@ -300,6 +331,7 @@ typedef enum event_t R_BANDWIDTH, R_BW_HALT, T_BANDWIDTH, + R_SNAPSHOT, //used for timed statistic outputs } event_t; /* whether the last hop of a packet was global, local or a terminal */ @@ -323,9 +355,19 @@ enum ROUTING_ALGO NON_MINIMAL, ADAPTIVE, PROG_ADAPTIVE, - PROG_ADAPTIVE_LEGACY + PROG_ADAPTIVE_LEGACY, + SMART_MINIMAL, + SMART_NON_MINIMAL, + SMART_PROG_ADAPTIVE }; +enum RAIL_SELECTION_ALGO +{ + RAIL_CONGESTION=1, // Selects rail with minimal injection congestion + RAIL_PATH, // Selects the rail that provides minimal path congestion is tie breaker + RAIL_DEDICATED, // Selects a specific rail + RAIL_RAND +}; static char* get_routing_alg_chararray(int routing_alg_int) { @@ -347,6 +389,15 @@ static char* get_routing_alg_chararray(int routing_alg_int) case PROG_ADAPTIVE_LEGACY: strcpy(rt_alg, "PROG_ADAPTIVE_LEGACY"); break; + case SMART_PROG_ADAPTIVE: + strcpy(rt_alg, "SMART_PROG_ADAPTIVE"); + break; + case SMART_MINIMAL: + strcpy(rt_alg, "SMART_MINIMAL"); + break; + case SMART_NON_MINIMAL: + strcpy(rt_alg, "SMART_NON_MINIMAL"); + break; default: tw_error(TW_LOC, "Routing Algorithm is UNDEFINED - did you call get_routing_alg_string() before setting the static global variable: 'routing'?"); break; @@ -356,15 +407,23 @@ static char* get_routing_alg_chararray(int routing_alg_int) static bool isRoutingAdaptive(int alg) { - if (alg == ADAPTIVE || alg == PROG_ADAPTIVE || alg == PROG_ADAPTIVE_LEGACY) + if (alg == ADAPTIVE || alg == PROG_ADAPTIVE || alg == PROG_ADAPTIVE_LEGACY || alg == SMART_PROG_ADAPTIVE) return true; else return false; } +static bool isRoutingSmart(int alg) +{ + if (alg == SMART_MINIMAL || alg == SMART_PROG_ADAPTIVE || alg == SMART_NON_MINIMAL) + return true; + else + return false; +} + static bool isRoutingMinimal(int alg) { - if (alg == MINIMAL) + if (alg == MINIMAL || alg == SMART_MINIMAL) return true; else return false; @@ -393,25 +452,35 @@ struct terminal_state int total_gen_size; // Dragonfly specific parameters - unsigned int router_id; + tw_lpid* router_lp; //one per rail + unsigned int* router_id; //one per rail unsigned int terminal_id; - int* vc_occupancy; // NUM_VC - tw_stime terminal_available_time; - terminal_dally_message_list **terminal_msgs; - terminal_dally_message_list **terminal_msgs_tail; - int in_send_loop; + DragonflyConnectionManager connMan; + tlc_state *local_congestion_controller; + + map workload_lpid_to_app_id; + set app_ids; + + int workloads_finished_flag; + + int** vc_occupancy; // vc_occupancies [rail_id][qos_level] + tw_stime* terminal_available_time; // [rail_id] + terminal_dally_message_list ***terminal_msgs; //[rail_id][qos_level] + terminal_dally_message_list ***terminal_msgs_tail; //[rail_id][qos_level] + int* in_send_loop; // [rail_id] struct mn_stats dragonfly_stats_array[CATEGORY_MAX]; - int * qos_status; - int * qos_data; + int ** qos_status; //[rail_id][qos_level] + int ** qos_data; //[rail_id][qos_level] - int last_qos_lvl; + int* last_qos_lvl; //[rail_id] int is_monitoring_bw; struct rc_stack * st; - int issueIdle; - int* terminal_length; + struct rc_stack * cc_st; + int* issueIdle; //[rail_id] + int** terminal_length; // [rail_id][qos_level] const char * anno; const dragonfly_param *params; @@ -426,11 +495,15 @@ struct terminal_state long finished_chunks; long finished_packets; - tw_stime last_buf_full; - tw_stime busy_time; - uint64_t link_traffic; + tw_stime* last_buf_full; //[rail_id] + tw_stime* busy_time; //[rail_id] + uint64_t* link_traffic; //[rail_id] - unsigned long stalled_chunks; //Counter for when a packet cannot be immediately routed due to full VC + unsigned long* total_chunks; //counter for when a packet is sent + unsigned long* stalled_chunks; //Counter for when a packet cannot be immediately routed due to full VC - [rail_id] + + unsigned long injected_chunks; //counter for chunks injected + unsigned long ejected_chunks; //counter for chucnks ejected from network tw_stime max_latency; tw_stime min_latency; @@ -443,7 +516,7 @@ struct terminal_state long data_size_sample; double fin_hops_sample; tw_stime fin_chunks_time; - tw_stime busy_time_sample; + tw_stime *busy_time_sample; char sample_buf[4096]; struct dfly_cn_sample * sample_stat; @@ -459,7 +532,7 @@ struct terminal_state long data_size_ross_sample; long fin_hops_ross_sample; tw_stime fin_chunks_time_ross_sample; - tw_stime busy_time_ross_sample; + tw_stime *busy_time_ross_sample; struct dfly_cn_sample ross_sample; }; @@ -467,13 +540,15 @@ struct router_state { unsigned int router_id; int group_id; + int plane_id; int op_arr_size; int max_arr_size; int* global_channel; - ConnectionManager *connMan; //manages and organizes connections from this router - + DragonflyConnectionManager connMan; //manages and organizes connections from this router + rlc_state *local_congestion_controller; + tw_stime* next_output_available_time; tw_stime* last_buf_full; @@ -481,6 +556,7 @@ struct router_state tw_stime* busy_time_sample; unsigned long* stalled_chunks; //Counter for when a packet is put into queued messages instead of routing due to full VC + unsigned long* total_chunks; //Counter for when a packet is sent - per port terminal_dally_message_list ***pending_msgs; terminal_dally_message_list ***pending_msgs_tail; @@ -489,7 +565,12 @@ struct router_state int *in_send_loop; int *queued_count; struct rc_stack * st; + struct rc_stack * cc_st; + int workloads_finished_flag; + + double* port_bandwidths; //used by CC + int* vc_max_sizes; //max for vc sizes indexed by port int** vc_occupancy; int64_t* link_traffic; int64_t * link_traffic_sample; @@ -502,6 +583,7 @@ struct router_state const char * anno; const dragonfly_param *params; + int** snapshot_data; //array of x numbers of snapshots of variable size char output_buf[4096]; struct dfly_router_sample * rsamples; @@ -513,6 +595,7 @@ struct router_state tw_stime* busy_time_ross_sample; int64_t * link_traffic_ross_sample; struct dfly_router_sample ross_rsample; + tw_stime last_time; }; @@ -588,10 +671,13 @@ void custom_dally_dragonfly_model_stat_collect(terminal_state *s, tw_lp *lp, cha index += sizeof(tmp2); s->fin_chunks_time_ross_sample = 0; - tmp2 = s->busy_time_ross_sample; - memcpy(&buffer[index], &tmp2, sizeof(tmp2)); - index += sizeof(tmp2); - s->busy_time_ross_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + { + tmp2 = s->busy_time_ross_sample[i]; + memcpy(&buffer[index], &tmp2, sizeof(tmp2)); + index += sizeof(tmp2); + s->busy_time_ross_sample[i] = 0; + } return; } @@ -707,7 +793,9 @@ static void ross_dally_dragonfly_sample_fn(terminal_state * s, tw_bf * bf, tw_lp sample->data_size_sample = s->ross_sample.data_size_sample; sample->fin_hops_sample = s->ross_sample.fin_hops_sample; sample->fin_chunks_time = s->ross_sample.fin_chunks_time; - sample->busy_time_sample = s->ross_sample.busy_time_sample; + sample->busy_time_sample = (tw_stime*)((&sample->busy_time_sample[0] + s->params->num_rails)); + for(int i = 0; i < s->params->num_rails; i++) + sample->busy_time_sample[i] = s->ross_sample.busy_time_sample[i]; sample->end_time = tw_now(lp); sample->fwd_events = s->ross_sample.fwd_events; sample->rev_events = s->ross_sample.rev_events; @@ -718,7 +806,8 @@ static void ross_dally_dragonfly_sample_fn(terminal_state * s, tw_bf * bf, tw_lp s->ross_sample.fwd_events = 0; s->ross_sample.rev_events = 0; s->ross_sample.fin_chunks_time = 0; - s->ross_sample.busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + s->ross_sample.busy_time_sample[i] = 0; } static void ross_dally_dragonfly_sample_rc_fn(terminal_state * s, tw_bf * bf, tw_lp * lp, struct dfly_cn_sample *sample) @@ -726,7 +815,8 @@ static void ross_dally_dragonfly_sample_rc_fn(terminal_state * s, tw_bf * bf, tw (void)lp; (void)bf; - s->ross_sample.busy_time_sample = sample->busy_time_sample; + for(int i = 0; i < s->params->num_rails; i++) + s->ross_sample.busy_time_sample[i] = sample->busy_time_sample[i]; s->ross_sample.fin_chunks_time = sample->fin_chunks_time; s->ross_sample.fin_hops_sample = sample->fin_hops_sample; s->ross_sample.data_size_sample = sample->data_size_sample; @@ -884,12 +974,17 @@ void dragonfly_dally_sample_init(terminal_state * s, s->data_size_sample = 0; s->fin_hops_sample = 0; s->fin_chunks_time = 0; - s->busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + s->busy_time_sample[i] = 0; s->op_arr_size = 0; s->max_arr_size = MAX_STATS; s->sample_stat = (dfly_cn_sample *)calloc(MAX_STATS, sizeof(struct dfly_cn_sample)); + for(int i = 0; i < s->max_arr_size; i++) + { + s->sample_stat[i].busy_time_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); + } } void dragonfly_dally_sample_rc_fn(terminal_state * s, @@ -904,7 +999,8 @@ void dragonfly_dally_sample_rc_fn(terminal_state * s, s->op_arr_size--; int cur_indx = s->op_arr_size; struct dfly_cn_sample stat = s->sample_stat[cur_indx]; - s->busy_time_sample = stat.busy_time_sample; + for(int i = 0; i < s->params->num_rails; i++) + s->busy_time_sample[i] = stat.busy_time_sample[i]; s->fin_chunks_time = stat.fin_chunks_time; s->fin_hops_sample = stat.fin_hops_sample; s->data_size_sample = stat.data_size_sample; @@ -912,7 +1008,8 @@ void dragonfly_dally_sample_rc_fn(terminal_state * s, s->fwd_events = stat.fwd_events; s->rev_events = stat.rev_events; - stat.busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + stat.busy_time_sample[i] = 0; stat.fin_chunks_time = 0; stat.fin_hops_sample = 0; stat.data_size_sample = 0; @@ -950,7 +1047,8 @@ void dragonfly_dally_sample_fn(terminal_state * s, s->sample_stat[cur_indx].data_size_sample = s->data_size_sample; s->sample_stat[cur_indx].fin_hops_sample = s->fin_hops_sample; s->sample_stat[cur_indx].fin_chunks_time = s->fin_chunks_time; - s->sample_stat[cur_indx].busy_time_sample = s->busy_time_sample; + for(int i = 0; i < s->params->num_rails; i++) + s->sample_stat[cur_indx].busy_time_sample[i] = s->busy_time_sample[i]; s->sample_stat[cur_indx].end_time = tw_now(lp); s->sample_stat[cur_indx].fwd_events = s->fwd_events; s->sample_stat[cur_indx].rev_events = s->rev_events; @@ -962,7 +1060,8 @@ void dragonfly_dally_sample_fn(terminal_state * s, s->fwd_events = 0; s->rev_events = 0; s->fin_chunks_time = 0; - s->busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + s->busy_time_sample[i] = 0; } void dragonfly_dally_sample_fin(terminal_state * s, @@ -1006,9 +1105,15 @@ static Connection dfdally_minimal_routing(router_state *s, tw_bf *bf, terminal_d static Connection dfdally_nonminimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); static Connection dfdally_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); static Connection dfdally_prog_adaptive_legacy_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfdally_smart_minimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfdally_smart_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfdally_smart_minimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfdally_smart_nonminimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); /*Routing Helper Declarations*/ static void dfdally_select_intermediate_group(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); +static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id); +static set< Connection> get_smart_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id, int max_global_hops_in_path); static tw_stime dragonfly_total_time = 0; static tw_stime dragonfly_max_latency = 0; @@ -1020,6 +1125,17 @@ static long long total_msg_sz = 0; static long long N_finished_msgs = 0; static long long N_finished_chunks = 0; +static tw_stime gen_noise(tw_lp *lp, short* rng_counter) +{ +#if ADD_NOISE == 1 + tw_stime noise = tw_rand_unif(lp->rng); + (*rng_counter)++; + return noise; +#else + return 0; +#endif +} + /* convert ns to seconds */ static tw_stime ns_to_s(tw_stime ns) { @@ -1087,6 +1203,35 @@ static void free_tmp(void * ptr) free(dfly); } +static int dfdally_get_assigned_router_id_from_terminal(const dragonfly_param *params, int term_gid, int rail_id) +{ + int num_planes = params->num_planes; + int num_rails = params->num_rails; + + int total_routers = params->total_routers; + int total_terminals = params->total_terminals; + int num_cn_per_router = params->num_cn; + + if(num_planes == 1) //then all rails go to the same router //TODO: this could change - could be cool! + { + if(num_rails == 1) //default behavior + return term_gid / num_cn_per_router; + else + { + return term_gid / num_cn_per_router; // all rails go to same router - perhaps change this + } + } + else + { + int routers_per_plane = total_routers / num_planes; + if(num_planes == num_rails) + { + return (term_gid / num_cn_per_router) + (rail_id * routers_per_plane); + } + } + +} + static int dfdally_score_connection(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, Connection conn, conn_minimality_t c_minimality) { int score = 0; @@ -1165,6 +1310,79 @@ static Connection get_absolute_best_connection_from_conns(router_state *s, tw_bf return best_conns[tw_rand_integer(lp->rng, 0, best_conns.size()-1)]; } +//Now returns random selection from tied best connections. +static Connection get_absolute_best_connection_from_conn_set(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, set< Connection > conns) +{ + if (conns.size() == 0) { //passed no connections to this but we got to return something - return negative filled conn to force a break if not caught + Connection bad_conn; + bad_conn.src_gid = -1; + bad_conn.port = -1; + return bad_conn; + } + if (conns.size() == 1) { //no need to compare singular connection + return (*(conns.begin())); + } + + int num_to_compare = conns.size(); + int scores[num_to_compare]; + vector < Connection > best_conns; + int best_score = INT_MAX; + + set::iterator it; + int count = 0; + for(it = conns.begin(); it != conns.end(); it++) + { + scores[count] = dfdally_score_connection(s, bf, msg, lp, *it, C_MIN); + if (scores[count] < best_score) { + best_score = scores[count]; + best_conns.clear(); + best_conns.push_back(*it); + } + else if (scores[count] == best_score) + { + best_conns.push_back(*it); + } + count++; + + } + + assert(best_conns.size() > 0); + + msg->num_rngs++; + return best_conns[tw_rand_integer(lp->rng, 0, best_conns.size()-1)]; +} + +// note that this is somewhat expensive the larger k is in comparison to the total possible +// consider an optimization to implement an efficient shuffle to poll k random sampling instead +// consider an optimization for the default of 2 +static Connection dfdally_get_best_from_k_connection_set(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, set< Connection > conns, int k) +{ + if (conns.size() == 0) + { + Connection bad_conn; + bad_conn.src_gid = -1; + bad_conn.port = -1; + return bad_conn; + } + if (conns.size() == 1) + { + return *(conns.begin()); + } + + vector k_conns; + set::iterator it = conns.begin(); + for(int i = 0; i < k; i++) + { + int offset = tw_rand_integer(lp->rng, 0, conns.size()-1); + msg->num_rngs++; + advance(it, offset); + k_conns.push_back(*it); + conns.erase(it); + it = conns.begin(); + } + return get_absolute_best_connection_from_conns(s, bf, msg, lp, k_conns); +} + // This is not the most efficient way to do things as k approaches the size(conns). // For low k it's more efficient than doing a full shuffle to sample a few random indices, though. static vector< Connection > dfdally_poll_k_connections(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, vector< Connection > conns, int k) @@ -1304,6 +1522,30 @@ static terminal_dally_message_list* return_tail( return tail; } +static tw_stime* buff_time_storage_create(terminal_state *s) +{ + tw_stime* storage = (tw_stime*)malloc(s->params->num_rails * sizeof(tw_stime)); + return storage; +} + +static void buff_time_storage_delete(void * ptr) +{ + if (ptr) + free(ptr); +} + +static int* int_storage_create(terminal_state *s) +{ + int* storage = (int*)malloc(s->params->num_rails * sizeof(int)); + return storage; +} + +static void int_storage_delete(void * ptr) +{ + if (ptr) + free(ptr); +} + void dragonfly_print_params(const dragonfly_param *p, FILE * st) { if(!st) @@ -1321,12 +1563,17 @@ void dragonfly_print_params(const dragonfly_param *p, FILE * st) fprintf(st,"\tcn_vc_size = %d\n",p->cn_vc_size); fprintf(st,"\tchunk_size = %d\n",p->chunk_size); fprintf(st,"\tnum_cn = %d\n",p->num_cn); + fprintf(st,"\tcn_radix = %d\n",p->cn_radix); fprintf(st,"\tintra_grp_radix = %d\n",p->intra_grp_radix); fprintf(st,"\tnum_groups = %d\n",p->num_groups); + fprintf(st,"\ttotal_groups = %d\n",p->total_groups); fprintf(st,"\tvirtual radix = %d\n",p->radix); fprintf(st,"\ttotal_routers = %d\n",p->total_routers); fprintf(st,"\ttotal_terminals = %d\n",p->total_terminals); fprintf(st,"\tnum_global_channels = %d\n",p->num_global_channels); + fprintf(st,"\tnum_injection_queues = %d\n",p->num_injection_queues); + fprintf(st,"\tnum_rails = %d\n",p->num_rails); + fprintf(st,"\tnum_planes = %d\n",p->num_planes); fprintf(st,"\tcn_delay = %.2f\n",p->cn_delay); fprintf(st,"\tlocal_delay = %.2f\n",p->local_delay); fprintf(st,"\tglobal_delay = %.2f\n",p->global_delay); @@ -1442,11 +1689,7 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) } else p->qos_bandwidths[0] = 100; - rc = configuration_get_value_double(&config, "PARAMS", "max_qos_monitor", anno, &max_qos_monitor); - if(rc) { - if(!myRank) - fprintf(stderr, "Setting max_qos_monitor to %lf\n", max_qos_monitor); - } + rc = configuration_get_value_int(&config, "PARAMS", "adaptive_threshold", anno, &p->adaptive_threshold); if (rc) { if(!myRank) @@ -1473,6 +1716,12 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) routing = PROG_ADAPTIVE; else if (strcmp(routing_str, "prog-adaptive-legacy") == 0) routing = PROG_ADAPTIVE_LEGACY; + else if (strcmp(routing_str, "smart-prog-adaptive") == 0) + routing = SMART_PROG_ADAPTIVE; + else if (strcmp(routing_str, "smart-minimal") == 0) + routing = SMART_MINIMAL; + else if (strcmp(routing_str, "smart-nonminimal") == 0) + routing = SMART_NON_MINIMAL; else { if(!myRank) @@ -1480,6 +1729,47 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) routing = MINIMAL; } + rc = configuration_get_value_int(&config, "PARAMS", "num_injection_queues", anno, &p->num_injection_queues); + if(rc) + p->num_injection_queues = 1; + + p->num_rails = 1; + rc = configuration_get_value_int(&config, "PARAMS", "num_rails", anno, &p->num_rails); + if (!rc) { + if (!myRank) + printf("num_rails set to %d\n",p->num_rails); + } + + p->num_planes = 1; + rc = configuration_get_value_int(&config, "PARAMS", "num_planes", anno, &p->num_planes); + if (!rc) { + if (!myRank) + printf("num_planes set to %d\n",p->num_planes); + // tw_error(TW_LOC, "Multi Planar Dragonfly not implemented yet\n"); + } + + p->num_rails_per_plane = p->num_rails / p->num_planes; + if (p->num_rails % p->num_planes != 0) + tw_error(TW_LOC, "Number of rails not evenly divisible by number of planes!\n"); + + char rail_select_str[MAX_NAME_LENGTH]; + rc = configuration_get_value(&config, "PARAMS", "rail_select", anno, rail_select_str, + MAX_NAME_LENGTH); + if(strcmp(rail_select_str, "dedicated") == 0) + p->rail_select = RAIL_DEDICATED; + else if(strcmp(rail_select_str, "congestion")==0) + p->rail_select = RAIL_CONGESTION; + else if(strcmp(rail_select_str, "path")==0) + p->rail_select = RAIL_PATH; + else if(strcmp(rail_select_str, "rand")==0) + p->rail_select = RAIL_RAND; + else { + p->rail_select = RAIL_DEDICATED; + } + if (p->num_rails == 1) + p->rail_select = RAIL_DEDICATED; + if(!myRank) printf("Dragonfly rail selection is %d\n", p->rail_select); + rc = configuration_get_value_int(&config, "PARAMS", "global_k_picks", anno, &p->global_k_picks); if(rc) { p->global_k_picks = 2; @@ -1543,23 +1833,25 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) fprintf(stderr,"Number of global channels per router not specified, setting to 10\n"); p->num_global_channels = 10; } - p->intra_grp_radix = p->num_routers -1; //TODO allow for parallel connections - p->radix = p->intra_grp_radix + p->num_global_channels + p->num_cn; - p->total_routers = p->num_groups * p->num_routers; - p->total_terminals = p->total_routers * p->num_cn; - - //setup Connection Managers for each router - for(int i = 0; i < p->total_routers; i++) - { - int src_id_global = i; - int src_id_local = i % p->num_routers; - int src_group = i / p->num_routers; - - ConnectionManager conman = ConnectionManager(src_id_local, src_id_global, src_group, p->intra_grp_radix, p->num_global_channels, p->num_cn, p->num_routers); - connManagerList.push_back(conman); + rc = configuration_get_value_int(&config, "PARAMS", "num_parallel_switch_conns", anno, &p->num_parallel_switch_conns); + if(rc) { + p->num_parallel_switch_conns = 1; } + + p->intra_grp_radix = (p->num_routers -1) * p->num_parallel_switch_conns; + p->cn_radix = (p->num_cn * p->num_rails) / p->num_planes; //number of CNs per router times number of rails taht each CN has, divided by how many planes those CNs are shared across + p->global_radix = p->num_global_channels * p->num_parallel_switch_conns; + p->radix = p->intra_grp_radix + p->global_radix + p->cn_radix; + p->total_groups = p->num_groups * p->num_planes; + p->total_routers = p->total_groups * p->num_routers; + p->total_terminals = p->total_routers * p->num_cn / p->num_planes; + p->num_routers_per_plane = p->total_routers / p->num_planes; + + //Setup DflyNetworkManager + netMan = DragonflyNetworkManager(p->total_routers, p->total_terminals, p->num_routers, p->intra_grp_radix, p->global_radix, p->cn_radix, p->num_rails, p->num_planes, max_hops_per_group, max_global_hops_nonminimal); + // read intra group connections, store from a router's perspective // all links to the same router form a vector char intraFile[MAX_NAME_LENGTH]; @@ -1580,13 +1872,20 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) int src_id_local = newLink.src; int dest_id_local = newLink.dest; - for(int i = 0; i < p->total_routers; i++) + for(int i = 0; i < p->total_routers; i++) //handles all routers in network, including multi planar { int group_id = i/p->num_routers; if (i % p->num_routers == src_id_local) { - int dest_id_gloabl = group_id * p->num_routers + dest_id_local; - connManagerList[i].add_connection(dest_id_gloabl, CONN_LOCAL); + int planar_id = i / p->num_routers_per_plane; + int dest_gid_global = (group_id * p->num_routers + dest_id_local); + + Link_Info new_link; + new_link.src_gid = i; + new_link.dest_gid = dest_gid_global; + new_link.conn_type = CONN_LOCAL; + new_link.rail_id = planar_id; + netMan.add_link(new_link); } } } @@ -1595,9 +1894,19 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) //terminal assignment for(int i = 0; i < p->total_terminals; i++) { - int assigned_router_id = (int) i / p->num_cn; - // int assigned_group_id = assigned_router_id / p->num_routers; - connManagerList[assigned_router_id].add_connection(i, CONN_TERMINAL); + for(int j = 0; j < p->num_rails; j++) + { + int assigned_router_id = dfdally_get_assigned_router_id_from_terminal(p, i, j); + + Link_Info new_link; + new_link.src_gid = assigned_router_id; + new_link.dest_gid = i; + new_link.conn_type = CONN_TERMINAL; + new_link.rail_id = j; + // printf("R%d <-> T%d P%d\n",new_link.src_gid, new_link.dest_gid, new_link.rail_id); + netMan.add_link(new_link); + } + } // read inter group connections, store from a router's perspective @@ -1612,7 +1921,7 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) if(!myRank) { fprintf(stderr, "Reading inter-group connectivity file: %s\n", interFile); - fprintf(stderr, "\n Total routers %d total groups %d ", p->total_routers, p->num_groups); + fprintf(stderr, "\n Total routers %d total groups %d ", p->total_routers, p->total_groups); } connectionList.resize(p->num_groups); @@ -1620,31 +1929,100 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) connectionList[g].resize(p->num_groups); } + vector< vector< vector > > connectionListEnumerated; //this one will have one final item for EACH link, not just to show existence of some unknown amount of links + connectionListEnumerated.resize(p->num_groups); + for(int g = 0; g < connectionListEnumerated.size(); g++) { + connectionListEnumerated[g].resize(p->num_groups); + } + InterGroupLink newInterLink; while (fread(&newInterLink, sizeof(InterGroupLink), 1, systemFile) != 0) { - int src_id_global = newInterLink.src; - int src_group_id = src_id_global / p->num_routers; - int dest_id_global = newInterLink.dest; - int dest_group_id = dest_id_global / p->num_routers; - connManagerList[src_id_global].add_connection(dest_id_global, CONN_GLOBAL); + for(int i = 0; i < p->num_planes; i++) + { + int read_src_id_global = newInterLink.src; + int read_src_group_id = read_src_id_global / p->num_routers; + int read_dest_id_global = newInterLink.dest; + int read_dest_group_id = read_dest_id_global / p->num_routers; + + int mapped_src_gid = read_src_id_global + (i*p->num_routers_per_plane); + int mapped_dest_gid = read_dest_id_global + (i*p->num_routers_per_plane); + + Link_Info new_link; + new_link.src_gid = mapped_src_gid; + new_link.dest_gid = mapped_dest_gid; + new_link.conn_type = CONN_GLOBAL; + new_link.rail_id = i; + // printf("R%d G-> R%d P%d\n",new_link.src_gid, new_link.dest_gid, new_link.rail_id); + netMan.add_link(new_link); + + if( i == 0) //only need to do this once, not every plane + { + // connManagerList[src_id_global].add_connection(dest_id_global, CONN_GLOBAL); + connectionListEnumerated[read_src_group_id][read_dest_group_id].push_back(newInterLink.src); + + int r; + for (r = 0; r < connectionList[read_src_group_id][read_dest_group_id].size(); r++) { + if (connectionList[read_src_group_id][read_dest_group_id][r] == newInterLink.src) + break; + } + if (r == connectionList[read_src_group_id][read_dest_group_id].size()) { + connectionList[read_src_group_id][read_dest_group_id].push_back(newInterLink.src); + } + } + + } + } + + + //read link failure file + char failureFileName[MAX_NAME_LENGTH]; + failureFileName[0] = '\0'; - int r; - for (r = 0; r < connectionList[src_group_id][dest_group_id].size(); r++) { - if (connectionList[src_group_id][dest_group_id][r] == newInterLink.src) - break; + if (strlen(g_nm_link_failure_filepath) == 0) //was this defined already via a command line argument? + { + configuration_get_value(&config, "PARAMS", "link-failure-file", + anno, failureFileName, MAX_NAME_LENGTH); + if (strlen(failureFileName) > 0) { + netMan.enable_link_failures(); } - if (r == connectionList[src_group_id][dest_group_id].size()) { - connectionList[src_group_id][dest_group_id].push_back(newInterLink.src); + } + else + { + strcpy(failureFileName, g_nm_link_failure_filepath); + netMan.enable_link_failures(); + } + + if(netMan.is_link_failures_enabled()) + { + if(!myRank) + printf("\nDragonfly Dally: Link Failures Feature Enabled\n"); + + FILE *failureFile = fopen(failureFileName, "rb"); + if (!failureFile) + tw_error(TW_LOC, "link failure file not found: %s\n",failureFileName); + + if (!myRank) + fprintf(stderr, "Reading link failure file: %s\n", failureFileName); + + Link_Info link; + while (fread(&link, sizeof(Link_Info), 1, failureFile) != 0) { + netMan.add_link_failure_info(link); } } + + netMan.solidify_network(); //finalize link failures and burn the network links into the connection managers if (DUMP_CONNECTIONS) { - if (!myRank) { - for (int i = 0; i < connManagerList.size(); i++) + if(!myRank) { + for (int i = 0; i < p->total_routers; i++) + { + netMan.get_connection_manager_for_router(i).print_connections(); + } + for (int i = 0; i < p->total_terminals; i++) { - connManagerList[i].print_connections(); + netMan.get_connection_manager_for_terminal(i).print_connections(); } } } @@ -1653,13 +2031,13 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) if(!myRank) { fprintf(stderr, "\n Total nodes %d routers %d groups %d routers per group %d radix %d\n\n", - p->num_cn * p->total_routers, p->total_routers, p->num_groups, + p->num_cn * p->total_routers, p->total_routers, p->total_groups, p->num_routers, p->radix); } rc = configuration_get_value_double(&config, "PARAMS", "cn_delay", anno, &p->cn_delay); if (rc) { - p->cn_delay = bytes_to_ns(p->chunk_size, p->cn_bandwidth); + p->cn_delay = bytes_to_ns(p->chunk_size, p->cn_bandwidth*p->num_rails); if(!myRank) fprintf(stderr, "cn_delay not specified, using default calculation: %.2f\n", p->cn_delay); } @@ -1749,6 +2127,31 @@ static void dragonfly_read_config(const char * anno, dragonfly_param *params) } //END CREDIT DELAY CONFIGURATION LOGIC ---------------- + // CONGESTION CONTROL + int cc_enabled; + rc = configuration_get_value_int(&config, "PARAMS", "congestion_control_enabled", anno, &cc_enabled); + if(rc) { + if(!myRank) + fprintf(stderr,"\nCongestion Control Not Enabled\n"); + } + else { + g_congestion_control_enabled = cc_enabled; + if(!myRank) { + if (cc_enabled) + fprintf(stderr,"\nCongestion Control Enabled\n"); + else + fprintf(stderr,"\nCongestion Control Disabled\n"); + + } + + if(cc_enabled) + { + congestion_control_register_terminal_lpname(LP_CONFIG_NM_TERM); + congestion_control_register_router_lpname(LP_CONFIG_NM_ROUT); + } + } + // END CONGESTION CONTROL + if (PRINT_CONFIG && !myRank) { dragonfly_print_params(p,stderr); } @@ -1803,6 +2206,9 @@ void dragonfly_dally_report_stats() MPI_Reduce(&nonmin_count, &total_nonmin_packets, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_CODES); } + // long long total_stalled_chunks; //helpful for debugging and determinism checking + // MPI_Reduce( &global_stalled_chunk_counter, &total_stalled_chunks, 1, MPI_LONG_LONG, MPI_SUM, 0, MPI_COMM_CODES); + /* print statistics */ if(!g_tw_mynode) { @@ -1820,6 +2226,58 @@ void dragonfly_dally_report_stats() return; } +static void dragonfly_dally_terminal_end_sim_notif(terminal_state *s, tw_bf *bf, model_net_wrap_msg *msg, tw_lp *lp) +{ + s->workloads_finished_flag = 1; +} + +static void dragonfly_dally_terminal_end_sim_notif_rc(terminal_state *s, tw_bf *bf, model_net_wrap_msg *msg, tw_lp *lp) +{ + s->workloads_finished_flag = 0; +} + + +static void dragonfly_dally_router_end_sim_notif(router_state *s, tw_bf *bf, model_net_wrap_msg *msg, tw_lp *lp) +{ + s->workloads_finished_flag = 1; +} + +static void dragonfly_dally_router_end_sim_notif_rc(router_state *s, tw_bf *bf, model_net_wrap_msg *msg, tw_lp *lp) +{ + s->workloads_finished_flag = 0; +} + +static void dragonfly_dally_terminal_congestion_event(terminal_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + cc_terminal_local_congestion_event(s->local_congestion_controller, bf, msg, lp); +} + +static void dragonfly_dally_terminal_congestion_event_rc(terminal_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + cc_terminal_local_congestion_event_rc(s->local_congestion_controller, bf, msg, lp); +} + +static void dragonfly_dally_terminal_congestion_event_commit(terminal_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + cc_terminal_local_congestion_event_commit(s->local_congestion_controller, bf, msg, lp); +} + +static void dragonfly_dally_router_congestion_event(router_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + cc_router_local_congestion_event(s->local_congestion_controller, bf, msg, lp); +} + +static void dragonfly_dally_router_congestion_event_rc(router_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + cc_router_local_congestion_event_rc(s->local_congestion_controller, bf, msg, lp); + +} + +static void dragonfly_dally_router_congestion_event_commit(router_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + cc_router_local_congestion_event_commit(s->local_congestion_controller, bf, msg, lp); +} + int get_vcg_from_category(terminal_dally_message * msg) { if(strcmp(msg->category, "high") == 0) @@ -1830,7 +2288,7 @@ int get_vcg_from_category(terminal_dally_message * msg) tw_error(TW_LOC, "\n priority needs to be specified with qos_levels>1 %d", msg->category); } -static int get_term_bandwidth_consumption(terminal_state * s, int qos_lvl) +static int get_term_bandwidth_consumption(terminal_state * s, int rail_id, int qos_lvl) { assert(qos_lvl >= Q_HIGH && qos_lvl <= Q_LOW); @@ -1842,7 +2300,7 @@ static int get_term_bandwidth_consumption(terminal_state * s, int qos_lvl) double max_bw_per_ns = max_bw / (1000.0 * 1000.0 * 1000.0); double max_bytes_per_win = max_bw_per_ns * bw_reset_window; // int percent_bw = (bw_consumed / s->params->cn_bandwidth) * 100; - int percent_bw = (((double)s->qos_data[qos_lvl]) / max_bytes_per_win) * 100; + int percent_bw = (((double)s->qos_data[rail_id][qos_lvl]) / max_bytes_per_win) * 100; // printf("\n At terminal %lf max bytes %d percent %d ", max_bytes_per_win, s->qos_data[qos_lvl], percent_bw); return percent_bw; } @@ -1851,7 +2309,7 @@ static int get_term_bandwidth_consumption(terminal_state * s, int qos_lvl) static int get_rtr_bandwidth_consumption(router_state * s, int qos_lvl, int output_port) { assert(qos_lvl >= Q_HIGH && qos_lvl <= Q_LOW); - assert(output_port < s->params->intra_grp_radix + s->params->num_global_channels + s->params->num_cn); + assert(output_port < s->params->intra_grp_radix + s->params->num_global_channels + s->params->cn_radix); int bandwidth = s->params->cn_bandwidth; if (output_port < s->params->intra_grp_radix) @@ -1875,17 +2333,19 @@ static int get_rtr_bandwidth_consumption(router_state * s, int qos_lvl, int outp void issue_bw_monitor_event_rc(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { - for(int i = 0 ; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - int num_qos_levels = s->params->num_qos_levels; + int num_rails = s->params->num_rails; + if(msg->rc_is_qos_set == 1) { - for(int i = 0; i < num_qos_levels; i++) + for(int i = 0; i < num_rails; i++) { - s->qos_data[i] = msg->rc_qos_data[i]; - s->qos_status[i] = msg->rc_qos_status[i]; + for(int j = 0; j < num_qos_levels; j++) + { + s->qos_data[i][j] = *(indexer2d(msg->rc_qos_data, i, j, num_rails, num_qos_levels)); + s->qos_status[i][j] =*(indexer2d(msg->rc_qos_status, i, j, num_rails, num_qos_levels)); + } } free(msg->rc_qos_data); @@ -1897,43 +2357,46 @@ void issue_bw_monitor_event_rc(terminal_state * s, tw_bf * bf, terminal_dally_me /* resets the bandwidth numbers recorded so far */ void issue_bw_monitor_event(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { - - msg->num_cll = 0; - msg->num_rngs = 0; int num_qos_levels = s->params->num_qos_levels; + int num_rails = s->params->num_rails; //RC data storage start. //Allocate memory here for these pointers that are stored in the events. FREE THESE IN RC OR IN COMMIT_F - msg->rc_qos_data = (unsigned long long *) calloc(num_qos_levels, sizeof(unsigned long long)); - msg->rc_qos_status = (int *) calloc(num_qos_levels, sizeof(int)); + msg->rc_qos_data = (unsigned long long *) calloc(num_rails*num_qos_levels, sizeof(unsigned long long)); + msg->rc_qos_status = (int *) calloc(num_rails*num_qos_levels, sizeof(int)); + //store qos data and status into the arrays. Pointers to the arrays are stored in events. - for(int i = 0; i < num_qos_levels; i++) + for(int i = 0; i < num_rails; i++) { - msg->rc_qos_data[i] = s->qos_data[i]; - msg->rc_qos_status[i] = s->qos_status[i]; + for(int j = 0; j < num_qos_levels; j++) + { + *(indexer2d(msg->rc_qos_data, i, j, num_rails, num_qos_levels)) = s->qos_data[i][j]; + *(indexer2d(msg->rc_qos_status, i, j, num_rails, num_qos_levels)) = s->qos_status[i][j]; + } } msg->rc_is_qos_set = 1; //RC data storage end. /* Reset the qos status and bandwidth consumption. */ - for(int i = 0; i < num_qos_levels; i++) + for(int i = 0; i < num_rails; i++) { - s->qos_status[i] = Q_ACTIVE; - s->qos_data[i] = 0; + for(int j = 0; j < num_qos_levels; j++) + { + s->qos_status[i][j] = Q_ACTIVE; + s->qos_data[i][j] = 0; + } } - if(tw_now(lp) > max_qos_monitor) - return; - - msg->num_cll++; - terminal_dally_message * m; - tw_stime bw_ts = bw_reset_window + codes_local_latency(lp); - tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, DRAGONFLY_DALLY, - (void**)&m, NULL); - m->type = T_BANDWIDTH; - m->magic = terminal_magic_num; - tw_event_send(e); + if (s->workloads_finished_flag == 0) { + terminal_dally_message * m; + tw_stime bw_ts = bw_reset_window + gen_noise(lp, &msg->num_rngs); + tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, DRAGONFLY_DALLY, + (void**)&m, NULL); + m->type = T_BANDWIDTH; + m->magic = terminal_magic_num; + tw_event_send(e); + } } void issue_rtr_bw_monitor_event_rc(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp) @@ -1941,9 +2404,6 @@ void issue_rtr_bw_monitor_event_rc(router_state *s, tw_bf *bf, terminal_dally_me int radix = s->params->radix; int num_qos_levels = s->params->num_qos_levels; - for(int i = 0 ; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - if(msg->rc_is_qos_set == 1) { for(int i = 0; i < radix; i++) @@ -1962,9 +2422,6 @@ void issue_rtr_bw_monitor_event_rc(router_state *s, tw_bf *bf, terminal_dally_me } void issue_rtr_bw_monitor_event(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp) { - msg->num_cll = 0; - msg->num_rngs = 0; - int radix = s->params->radix; int num_qos_levels = s->params->num_qos_levels; @@ -1994,9 +2451,9 @@ void issue_rtr_bw_monitor_event(router_state *s, tw_bf *bf, terminal_dally_messa int bw_consumed = get_rtr_bandwidth_consumption(s, j, i); #if DEBUG_QOS == 1 - if(dragonfly_rtr_bw_log != NULL) + if(dragonfly_rtr_bw_log != NULL && ROUTER_BW_LOG) { - if(s->qos_data[j][k] > 0) + if(s->qos_data[i][j] > 0) { fprintf(dragonfly_rtr_bw_log, "\n %d %f %d %d %d %d %d %f", s->router_id, tw_now(lp), i, j, bw_consumed, s->qos_status[i][j], s->qos_data[i][j], s->busy_time_sample[i]); } @@ -2017,17 +2474,15 @@ void issue_rtr_bw_monitor_event(router_state *s, tw_bf *bf, terminal_dally_messa s->ross_rsample.busy_time[i] = 0; } - if(tw_now(lp) > max_qos_monitor) - return; - - msg->num_cll++; - tw_stime bw_ts = bw_reset_window + codes_local_latency(lp); - terminal_dally_message *m; - tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, - DRAGONFLY_DALLY_ROUTER, (void**)&m, NULL); - m->type = R_BANDWIDTH; - m->magic = router_magic_num; - tw_event_send(e); + if (s->workloads_finished_flag == 0) { + tw_stime bw_ts = bw_reset_window + gen_noise(lp, &msg->num_rngs); + terminal_dally_message *m; + tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, + DRAGONFLY_DALLY_ROUTER, (void**)&m, NULL); + m->type = R_BANDWIDTH; + m->magic = router_magic_num; + tw_event_send(e); + } } static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) @@ -2036,7 +2491,7 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_dally_message * if(num_qos_levels == 1) { - if(s->terminal_msgs[0] == NULL || s->vc_occupancy[0] + s->params->chunk_size > s->params->cn_vc_size) + if(s->terminal_msgs[msg->rail_id][0] == NULL || s->vc_occupancy[msg->rail_id][0] + s->params->chunk_size > s->params->cn_vc_size) return -1; else return 0; @@ -2047,9 +2502,9 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_dally_message * /* First make sure the bandwidth consumptions are up to date. */ for(int k = 0; k < num_qos_levels; k++) { - if(s->qos_status[k] != Q_OVERBW) + if(s->qos_status[msg->rail_id][k] != Q_OVERBW) { - bw_consumption[k] = get_term_bandwidth_consumption(s, k); + bw_consumption[k] = get_term_bandwidth_consumption(s, msg->rail_id, k); if(bw_consumption[k] > s->params->qos_bandwidths[k]) { if(k == 0) @@ -2057,7 +2512,7 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_dally_message * else if(k == 1) msg->qos_reset2 = 1; - s->qos_status[k] = Q_OVERBW; + s->qos_status[msg->rail_id][k] = Q_OVERBW; } } } @@ -2067,27 +2522,27 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_dally_message * { for(int i = 0; i < num_qos_levels; i++) { - if(s->qos_status[i] == Q_ACTIVE) + if(s->qos_status[msg->rail_id][i] == Q_ACTIVE) { - if(s->terminal_msgs[i] != NULL && s->vc_occupancy[i] + s->params->chunk_size <= s->params->cn_vc_size) + if(s->terminal_msgs[msg->rail_id][i] != NULL && s->vc_occupancy[msg->rail_id][i] + s->params->chunk_size <= s->params->cn_vc_size) return i; } } } - int next_rr_vcg = (s->last_qos_lvl + 1) % num_qos_levels; + int next_rr_vcg = (s->last_qos_lvl[msg->rail_id] + 1) % num_qos_levels; /* All vcgs are exceeding their bandwidth limits*/ for(int i = 0; i < num_qos_levels; i++) { - if(s->terminal_msgs[i] != NULL && s->vc_occupancy[i] + s->params->chunk_size <= s->params->cn_vc_size) + if(s->terminal_msgs[msg->rail_id][i] != NULL && s->vc_occupancy[msg->rail_id][i] + s->params->chunk_size <= s->params->cn_vc_size) { bf->c2 = 1; if(msg->last_saved_qos < 0) - msg->last_saved_qos = s->last_qos_lvl; + msg->last_saved_qos = s->last_qos_lvl[msg->rail_id]; - s->last_qos_lvl = next_rr_vcg; + s->last_qos_lvl[msg->rail_id] = next_rr_vcg; return i; } next_rr_vcg = (next_rr_vcg + 1) % num_qos_levels; @@ -2170,10 +2625,58 @@ static int get_next_router_vcg(router_state * s, tw_bf * bf, terminal_dally_mess return -1; } -void terminal_dally_commit(terminal_state * s, - tw_bf * bf, - terminal_dally_message * msg, - tw_lp * lp) +//Snapshot pattern +//Sends a snapshot event - this wakes the router at the specified time to store its data somewhere +//this storage place could be in the event or elsewehre so long as the data is over-writeable +//in case the event gets rolled back and replayed. +//On commit of the snapshot event, the commit function looks where the data was stored and outputs to lpio +void router_send_snapshot_events(router_state *s, tw_lp *lp) +{ + int len = sprintf(snapshot_filename, "dragonfly-snapshots.csv"); + snapshot_filename[len] = '\0'; + if (s->router_id == 0) //add header information + { + if (OUTPUT_SNAPSHOT) + { + char snapshot_line[1024]; + int written; + + written = sprintf(snapshot_line, "#Time of snapshot, Router ID, Port 0 VC 0, Port 0 VC 1 ... Port N VC M\n#Radix = %d Num VCs = %d\n",s->params->radix, s->params->num_vcs); + lp_io_write(lp->gid, snapshot_filename, written, snapshot_line); + } + } + + + for(int i = 0; i < num_snapshots; i++) + { + terminal_dally_message *m; + tw_event * e = model_net_method_event_new(lp->gid, snapshot_times[i], lp, DRAGONFLY_DALLY, (void**)&m, NULL); + m->type = R_SNAPSHOT; + m->magic = router_magic_num; + m->packet_ID = i; //just borrowing this field for our use + tw_event_send(e); + } + // printf("%d: sending snapshot events\n",s->router_id); +} + +void router_handle_snapshot_event(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp) +{ + for(int i = 0; i < s->params->radix; i++) + { + for(int j = 0; j < s->params->num_vcs; j++) + { + //msg->packet_ID contains which snapshot we're collecting + int snapshot_array_i = (i * s->params->num_vcs) + j; + s->snapshot_data[msg->packet_ID][snapshot_array_i] = s->vc_occupancy[i][j]; + // printf("%d: stored snapshot %d at time %.2f\n",s->router_id, msg->packet_ID, tw_now(lp)); + } + } +} + +void terminal_dally_commit(terminal_state * s, + tw_bf * bf, + terminal_dally_message * msg, + tw_lp * lp) { if(msg->type == T_BANDWIDTH) { @@ -2183,6 +2686,25 @@ void terminal_dally_commit(terminal_state * s, msg->rc_is_qos_set = 0; } } + + if(msg->type == T_ARRIVE) + { + if (OUTPUT_END_END_LATENCIES) + { + if (msg->message_id % OUTPUT_LATENCY_MODULO == 0) { + int written1; + char end_end_filename[128]; + written1 = sprintf(end_end_filename, "end-to-end-latency-hops"); + end_end_filename[written1] = '\0'; + + char latency[32]; + int written; + tw_stime lat = msg->travel_end_time-msg->travel_start_time; + written = sprintf(latency, "%d %.5f %d\n",msg->app_id, msg->travel_end_time-msg->travel_start_time,msg->my_N_hop); + lp_io_write(lp->gid, end_end_filename, written, latency); + } + } + } } void router_dally_commit(router_state * s, @@ -2198,6 +2720,49 @@ void router_dally_commit(router_state * s, msg->rc_is_qos_set = 0; } } + + if(msg->type == R_SEND) + { + if (bf->c1 == 0) { //did the R_SEND event actually complete a send? + if (OUTPUT_PORT_PORT_LATENCIES) + { + if (msg->message_id % OUTPUT_LATENCY_MODULO == 0) { + int written1; + char port_port_filename[128]; + written1 = sprintf(port_port_filename, "port-to-port-latencies"); + port_port_filename[written1] = '\0'; + + char latency[32]; + int written; + written = sprintf(latency, "%d %.5f\n",msg->app_id, msg->this_router_ptp_latency); + lp_io_write(lp->gid, port_port_filename, written, latency); + } + } + } + } + + if (msg->type == R_SNAPSHOT) + { + if (OUTPUT_SNAPSHOT == 1) + { + char snapshot_line[8192]; + int written; + + written = sprintf(snapshot_line, "%.4f, %d, ",snapshot_times[msg->packet_ID],s->router_id); + + for(int i = 0; i < s->params->radix; i++) + { + for(int j = 0; j < s->params->num_vcs; j++) + { + int snapshot_array_i = (i * s->params->num_vcs) + j; + int this_vc_snapshot_data = s->snapshot_data[msg->packet_ID][snapshot_array_i]; + written += sprintf(snapshot_line+written, "%d, ", this_vc_snapshot_data); + } + } + written += sprintf(snapshot_line+written, "\n"); + lp_io_write(lp->gid, snapshot_filename, written, snapshot_line); + } + } } /* initialize a dragonfly compute node terminal */ @@ -2225,64 +2790,110 @@ void terminal_dally_init( terminal_state * s, tw_lp * lp ) s->params = &all_params[id]; } - int num_qos_levels = s->params->num_qos_levels; - int num_lps = codes_mapping_get_lp_count(lp_group_name, 1, LP_CONFIG_NM_TERM, - s->anno, 0); + const dragonfly_param * p = s->params; + + int num_qos_levels = s->params->num_qos_levels; + int num_lps = codes_mapping_get_lp_count(lp_group_name, 1, LP_CONFIG_NM_TERM, + s->anno, 0); s->terminal_id = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); - s->router_id=(int)s->terminal_id / (s->params->num_cn); - s->terminal_available_time = 0.0; + s->router_id = (unsigned int*)calloc(p->num_rails, sizeof(unsigned int)); + s->router_lp = (tw_lpid*)calloc(p->num_rails, sizeof(tw_lpid)); + + s->connMan = netMan.get_connection_manager_for_terminal(s->terminal_id); + + + for(i = 0; i < p->num_rails; i++) + { + s->router_id[i] = dfdally_get_assigned_router_id_from_terminal(s->params,s->terminal_id,i); + num_routers_per_mgrp = codes_mapping_get_lp_count (lp_group_name, 1, "modelnet_dragonfly_dally_router", + NULL, 0); + codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM_ROUT, NULL, 1, s->router_id[i] / num_routers_per_mgrp, s->router_id[i] % num_routers_per_mgrp, &s->router_lp[i]); + } + + s->workload_lpid_to_app_id = map(); + s->app_ids = set(); + + s->terminal_available_time = (tw_stime*)calloc(p->num_rails, sizeof(tw_stime)); s->packet_counter = 0; s->min_latency = INT_MAX; s->max_latency = 0; - s->link_traffic=0.0; + s->link_traffic=(uint64_t*)calloc(p->num_rails, sizeof(uint64_t)); s->finished_msgs = 0; s->finished_chunks = 0; s->finished_packets = 0; s->total_time = 0.0; s->total_msg_size = 0; - s->stalled_chunks = 0; - s->busy_time = 0.0; + s->stalled_chunks = (unsigned long*)calloc(p->num_rails, sizeof(uint64_t)); + s->total_chunks = (unsigned long*)calloc(p->num_rails, sizeof(uint64_t)); + + s->injected_chunks = 0; + s->ejected_chunks = 0; + + s->busy_time = (tw_stime*)calloc(p->num_rails, sizeof(tw_stime)); s->fwd_events = 0; s->rev_events = 0; - rc_stack_create(&s->st); - s->vc_occupancy = (int*)calloc(num_qos_levels, sizeof(int)); //1 vc times the number of qos levels - s->last_buf_full = 0.0; + s->workloads_finished_flag = 0; - s->terminal_length = (int*)calloc(num_qos_levels, sizeof(int)); //1 vc times number of qos levels + rc_stack_create(&s->st); + rc_stack_create(&s->cc_st); + s->vc_occupancy = (int**)calloc(p->num_rails, sizeof(int*)); //1 vc times the number of qos levels + s->last_buf_full = (tw_stime*)calloc(p->num_rails, sizeof(tw_stime)); - /* Whether the virtual channel group is active or over-bw*/ - s->qos_status = (int*)calloc(num_qos_levels, sizeof(int)); + s->terminal_length = (int**)calloc(p->num_rails, sizeof(int*)); //1 vc times number of qos levels - /* How much data has been transmitted on the virtual channel group within - * the window */ - s->qos_data = (int*)calloc(num_qos_levels, sizeof(int)); - - for(i = 0; i < num_qos_levels; i++) + for(i = 0; i < p->num_rails; i++) { - s->qos_data[i] = 0; - s->qos_status[i] = Q_ACTIVE; - s->vc_occupancy[i]=0; + s->vc_occupancy[i]= (int*)calloc(num_qos_levels, sizeof(int)); + s->terminal_length[i]= (int*)calloc(num_qos_levels, sizeof(int)); } - s->last_qos_lvl = 0; + s->in_send_loop = (int*)calloc(p->num_rails, sizeof(int)); + s->issueIdle = (int*)calloc(p->num_rails, sizeof(int)); + s->rank_tbl = NULL; s->terminal_msgs = - (terminal_dally_message_list**)calloc(num_qos_levels, sizeof(terminal_dally_message_list*)); + (terminal_dally_message_list***)calloc(p->num_rails, sizeof(terminal_dally_message_list**)); s->terminal_msgs_tail = - (terminal_dally_message_list**)calloc(num_qos_levels, sizeof(terminal_dally_message_list*)); + (terminal_dally_message_list***)calloc(p->num_rails, sizeof(terminal_dally_message_list**)); - for(int i = 0; i < num_qos_levels; i++) + s->qos_status = (int**)calloc(p->num_rails, sizeof(int*)); + s->qos_data = (int**)calloc(p->num_rails, sizeof(int*)); + + for(i = 0; i < p->num_rails; i++) { - s->terminal_msgs[i] = NULL; - s->terminal_msgs_tail[i] = NULL; + s->in_send_loop[i] = 0; + s->terminal_msgs[i] = (terminal_dally_message_list**)calloc(num_qos_levels, sizeof(terminal_dally_message_list*)); + s->terminal_msgs_tail[i] = (terminal_dally_message_list**)calloc(num_qos_levels, sizeof(terminal_dally_message_list*)); + + for(int j = 0; j < num_qos_levels; j++) + { + s->terminal_msgs[i][j] = NULL; + s->terminal_msgs_tail[i][j] = NULL; + } + + /* Whether the virtual channel group is active or over-bw*/ + s->qos_status[i] = (int*)calloc(num_qos_levels, sizeof(int)); + + /* How much data has been transmitted on the virtual channel group within + * the window */ + s->qos_data[i] = (int*)calloc(num_qos_levels, sizeof(int)); + for(int j = 0; j < num_qos_levels; j++) + { + s->qos_data[i][j] = 0; + s->qos_status[i][j] = Q_ACTIVE; + } } - s->in_send_loop = 0; - s->issueIdle = 0; + s->last_qos_lvl = (int*)calloc(p->num_rails, sizeof(int)); + + + s->ross_sample.busy_time_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); + s->busy_time_ross_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); + s->busy_time_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); /*if(s->terminal_id == 0) { @@ -2291,6 +2902,11 @@ void terminal_dally_init( terminal_state * s, tw_lp * lp ) dragonfly_term_bw_log = fopen(term_bw_log, "w"); fprintf(dragonfly_term_bw_log, "\n term-id time-stamp port-id busy-time"); }*/ + + if (g_congestion_control_enabled) { + s->local_congestion_controller = (tlc_state*)calloc(1,sizeof(tlc_state)); + cc_terminal_local_controller_init(s->local_congestion_controller, lp, s->terminal_id, &s->workloads_finished_flag); + } return; } @@ -2298,7 +2914,6 @@ void terminal_dally_init( terminal_state * s, tw_lp * lp ) * local channels, compute node channels */ void router_dally_init(router_state * r, tw_lp * lp) { - char anno[MAX_NAME_LENGTH]; codes_mapping_get_lp_info(lp->gid, lp_group_name, &mapping_grp_id, NULL, &mapping_type_id, anno, &mapping_rep_id, &mapping_offset); @@ -2324,12 +2939,13 @@ void router_dally_init(router_state * r, tw_lp * lp) p->num_routers, p->total_routers, num_grp_reps * num_routers_per_mgrp); r->router_id = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); + r->plane_id = r->router_id / p->num_routers_per_plane; r->group_id=r->router_id/p->num_routers; char rtr_bw_log[128]; sprintf(rtr_bw_log, "router-bw-tracker-%lu", g_tw_mynode); - if(dragonfly_rtr_bw_log == NULL) + if(dragonfly_rtr_bw_log == NULL && ROUTER_BW_LOG) { dragonfly_rtr_bw_log = fopen(rtr_bw_log, "w+"); @@ -2346,7 +2962,31 @@ void router_dally_init(router_state * r, tw_lp * lp) int num_qos_levels = p->num_qos_levels; - r->connMan = &connManagerList[r->router_id]; + r->connMan = netMan.get_connection_manager_for_router(r->router_id); + + r->vc_max_sizes = (int*)calloc(p->radix, sizeof(int)); + for(int i = 0; i < p->radix; i++) + { + ConnectionType conn_type = r->connMan.get_port_type(i); + if (conn_type == CONN_LOCAL) + r->vc_max_sizes[i] = p->local_vc_size; + else if (conn_type == CONN_GLOBAL) + r->vc_max_sizes[i] = p->global_vc_size; + else + r->vc_max_sizes[i] = p->cn_vc_size; + } + + r->port_bandwidths = (double*)calloc(p->radix, sizeof(double)); + for(int i = 0; i < p->radix; i++) + { + ConnectionType conn_type = r->connMan.get_port_type(i); + if (conn_type == CONN_LOCAL) + r->port_bandwidths[i] = p->local_bandwidth; + else if (conn_type == CONN_GLOBAL) + r->port_bandwidths[i] = p->global_bandwidth; + else + r->port_bandwidths[i] = p->cn_bandwidth; + } r->global_channel = (int*)calloc(p->num_global_channels, sizeof(int)); r->next_output_available_time = (tw_stime*)calloc(p->radix, sizeof(tw_stime)); @@ -2354,6 +2994,9 @@ void router_dally_init(router_state * r, tw_lp * lp) r->link_traffic_sample = (int64_t*)calloc(p->radix, sizeof(int64_t)); r->stalled_chunks = (unsigned long*)calloc(p->radix, sizeof(unsigned long)); + r->total_chunks = (unsigned long*)calloc(p->radix, sizeof(unsigned long)); + + r->workloads_finished_flag = 0; r->vc_occupancy = (int**)calloc(p->radix , sizeof(int*)); r->in_send_loop = (int*)calloc(p->radix, sizeof(int)); @@ -2384,6 +3027,7 @@ void router_dally_init(router_state * r, tw_lp * lp) r->ross_rsample.link_traffic_sample = (int64_t*)calloc(p->radix, sizeof(int64_t)); rc_stack_create(&r->st); + rc_stack_create(&r->cc_st); for(int i=0; i < p->radix; i++) { @@ -2423,7 +3067,44 @@ void router_dally_init(router_state * r, tw_lp * lp) } } - r->connMan->solidify_connections(); + if (!r->connMan.check_is_solidified()) + tw_error(TW_LOC, "Connection Manager not solidified - should be performed after loading topology"); + + if (g_congestion_control_enabled) { + r->local_congestion_controller = (rlc_state*)calloc(1,sizeof(rlc_state)); + cc_router_local_controller_init(r->local_congestion_controller, lp, p->total_terminals, r->router_id, p->radix, p->num_vcs, r->vc_max_sizes, r->port_bandwidths, &r->workloads_finished_flag); + + vector terminal_out_conns = r->connMan.get_connections_by_type(CONN_TERMINAL); + vector::iterator it = terminal_out_conns.begin(); + for(; it != terminal_out_conns.end(); it++) + { + cc_router_local_controller_add_output_port(r->local_congestion_controller, it->port); + } + + // vector local_conns = r->connMan.get_connections_by_type(CONN_LOCAL); + // it = local_conns.begin(); + // for(; it != local_conns.end(); it++) + // { + // cc_router_local_controller_add_output_port(r->local_congestion_controller, it->port); + // } + + // vector global_conns = r->connMan.get_connections_by_type(CONN_GLOBAL); + // it = global_conns.begin(); + // for(; it != global_conns.end(); it++) + // { + // cc_router_local_controller_add_output_port(r->local_congestion_controller, it->port); + // } + + } + + if (num_snapshots) { + r->snapshot_data = (int**)calloc(num_snapshots, sizeof(int*)); + for(int i = 0; i < num_snapshots; i++) + { + r->snapshot_data[i] = (int*)calloc(r->params->num_vcs * r->params->radix, sizeof(int)); //capturing VC occupancies of each port + } + router_send_snapshot_events(r, lp); + } return; } @@ -2431,7 +3112,9 @@ void router_dally_init(router_state * r, tw_lp * lp) /* dragonfly packet event reverse handler */ static void dragonfly_dally_packet_event_rc(tw_lp *sender) { +#if ADD_NOISE == 1 codes_local_latency_reverse(sender); +#endif return; } @@ -2454,7 +3137,11 @@ static tw_stime dragonfly_dally_packet_event( terminal_dally_message * msg; char* tmp_ptr; - xfer_to_nic_time = codes_local_latency(sender); +#if ADD_NOISE == 1 + xfer_to_nic_time = codes_local_latency(sender); +#else + xfer_to_nic_time = 0; +#endif //e_new = tw_event_new(sender->gid, xfer_to_nic_time+offset, sender); //msg = tw_event_data(e_new); e_new = model_net_method_event_new(sender->gid, xfer_to_nic_time+offset, @@ -2465,17 +3152,20 @@ static tw_stime dragonfly_dally_packet_event( msg->sender_lp=req->src_lp; msg->sender_mn_lp = sender->gid; msg->packet_size = packet_size; - msg->travel_start_time = tw_now(sender); + //msg->travel_start_time = tw_now(sender); msg->remote_event_size_bytes = 0; msg->local_event_size_bytes = 0; msg->type = T_GENERATE; msg->dest_terminal_lpid = req->dest_mn_lp; + msg->dfdally_src_terminal_id = codes_mapping_get_lp_relative_id(msg->sender_mn_lp,0,0); msg->dfdally_dest_terminal_id = codes_mapping_get_lp_relative_id(msg->dest_terminal_lpid,0,0); msg->message_id = req->msg_id; msg->is_pull = req->is_pull; msg->pull_size = req->pull_size; msg->magic = terminal_magic_num; msg->msg_start_time = req->msg_start_time; + msg->rail_id = req->queue_offset; + msg->app_id = req->app_id; if(is_last_pckt) /* Its the last packet so pass in remote and local event information*/ { @@ -2515,12 +3205,6 @@ static void packet_generate_rc(terminal_state * s, tw_bf * bf, terminal_dally_me if(bf->c4) num_remote_packets--; - for(int i = 0; i < msg->num_rngs; i++) - tw_rand_reverse_unif(lp->rng); - - for(int i = 0; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - int num_chunks = msg->packet_size/s->params->chunk_size; if(msg->packet_size < s->params->chunk_size) num_chunks++; @@ -2535,19 +3219,33 @@ static void packet_generate_rc(terminal_state * s, tw_bf * bf, terminal_dally_me assert(vcg < num_qos_levels); for(i = 0; i < num_chunks; i++) { - delete_terminal_dally_message_list(return_tail(s->terminal_msgs, s->terminal_msgs_tail, vcg)); - s->terminal_length[vcg] -= s->params->chunk_size; + delete_terminal_dally_message_list(return_tail(s->terminal_msgs[msg->rail_id], s->terminal_msgs_tail[msg->rail_id], vcg)); + s->terminal_length[msg->rail_id][vcg] -= s->params->chunk_size; } if(bf->c5) { - s->in_send_loop = 0; + s->in_send_loop[msg->rail_id] = 0; } - if (bf->c11) { - s->issueIdle = 0; - s->stalled_chunks--; - if(bf->c8) { - s->last_buf_full = msg->saved_busy_time; + if (s->params->num_injection_queues > 1) { + // int* scs = (int*)rc_stack_pop(s->st); + int* iis = (int*)rc_stack_pop(s->st); + tw_stime* bts = (tw_stime*)rc_stack_pop(s->st); + + for(int j = 0; j < s->params->num_injection_queues; j++) + { + s->last_buf_full[j] = bts[j]; + s->issueIdle[j] = iis[j]; + // s->stalled_chunks[j] = scs[j]; } + buff_time_storage_delete(bts); + int_storage_delete(iis); + // int_storage_delete(scs); + } + + if (bf->c11) { + s->issueIdle[msg->rail_id] = 0; + if(bf->c8) + s->last_buf_full[msg->rail_id] = msg->saved_busy_time; } struct mn_stats* stat; stat = model_net_find_stats(msg->category, s->dragonfly_stats_array); @@ -2558,50 +3256,19 @@ static void packet_generate_rc(terminal_state * s, tw_bf * bf, terminal_dally_me /* generates packet at the current dragonfly compute node */ static void packet_generate(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { - - msg->num_rngs = 0; - msg->num_cll = 0; - packet_gen++; - int num_qos_levels = s->params->num_qos_levels; - int vcg = 0; - - if(num_qos_levels > 1) - { - tw_lpid router_id; - codes_mapping_get_lp_info(lp->gid, lp_group_name, &mapping_grp_id, NULL, - &mapping_type_id, NULL, &mapping_rep_id, &mapping_offset); - codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM_ROUT, NULL, 0, - s->router_id / num_routers_per_mgrp, s->router_id % num_routers_per_mgrp, &router_id); - if(s->is_monitoring_bw == 0) - { - bf->c1 = 1; - /* Issue an event on both terminal and router to monitor bandwidth */ - msg->num_cll++; - tw_stime bw_ts = bw_reset_window + codes_local_latency(lp); - terminal_dally_message * m; - tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, DRAGONFLY_DALLY, - (void**)&m, NULL); - m->type = T_BANDWIDTH; - m->magic = terminal_magic_num; - s->is_monitoring_bw = 1; - tw_event_send(e); - } - vcg = get_vcg_from_category(msg); - assert(vcg == Q_HIGH || vcg == Q_MEDIUM); - } - assert(vcg < num_qos_levels); s->packet_gen++; s->total_gen_size += msg->packet_size; - tw_stime ts, nic_ts; + tw_stime ts, injection_ts, nic_ts; assert(lp->gid != msg->dest_terminal_lpid); const dragonfly_param *p = s->params; int total_event_size; uint64_t num_chunks = msg->packet_size / p->chunk_size; + double cn_delay = s->params->cn_delay; if (msg->packet_size < s->params->chunk_size) @@ -2610,13 +3277,172 @@ static void packet_generate(terminal_state * s, tw_bf * bf, terminal_dally_messa if(msg->packet_size < s->params->chunk_size) cn_delay = bytes_to_ns(msg->packet_size % s->params->chunk_size, s->params->cn_bandwidth); - int dest_router_id = codes_mapping_get_lp_relative_id(msg->dest_terminal_lpid, 0, 0) / s->params->num_cn; - int dest_grp_id = dest_router_id / s->params->num_routers; - int src_grp_id = s->router_id / s->params->num_routers; + int dest_router_id; + if (s->params->num_injection_queues > 1 || netMan.is_link_failures_enabled()) { + //get rails available: should be from rails known to not be failed + vector< Connection > injection_connections = s->connMan.get_connections_by_type(CONN_INJECTION, false); + if(injection_connections.size() < 1) + tw_error(TW_LOC, "Packet Generation Failure: No non-failed injection connections available on terminal %d\n", s->terminal_id); + + vector< Connection > valid_rails; + if (netMan.is_link_failures_enabled()) + { + for (int i = 0; i < injection_connections.size(); i++) + { + int rail_id = injection_connections[i].rail_or_planar_id; + int dest_router_id = dfdally_get_assigned_router_id_from_terminal(s->params, msg->dfdally_dest_terminal_id, rail_id); + int src_router_id = dfdally_get_assigned_router_id_from_terminal(s->params, s->terminal_id, rail_id); + int src_group_id = src_router_id / s->params->num_routers; + int dest_group_id = dest_router_id / s->params->num_routers; + + if (isRoutingMinimal(routing)) { + if (src_group_id == dest_group_id) + { + set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,0); //max global hops for local group routing == 0 + if (valid_next_stops.size() > 0) + valid_rails.push_back(injection_connections[i]); + } + else + { + set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,1); //max global hops for local group routing == 0 + if (valid_next_stops.size() > 0) + valid_rails.push_back(injection_connections[i]); + } + } + else + { + // if (src_group_id == dest_group_id) + // { + // set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,0); //max global hops for local group routing == 0 + // if (valid_next_stops.size() > 0) + // valid_rails.push_back(injection_connections[i]); + // } + // else + // { + set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,max_global_hops_nonminimal); //max global hops for local group routing == 0 + if (valid_next_stops.size() > 0) + valid_rails.push_back(injection_connections[i]); + // } + } + } + if (valid_rails.size() < 1) { + tw_error(TW_LOC,"Invalid Connections in Network due to link failures!\n"); + // valid_rails = injection_connections; //TODO will cause problems - deal with + } + } + else { + valid_rails = injection_connections; + } + + vector< Connection > tied_rails; + + //determine rail + Connection target_rail_connection = valid_rails[0]; + if (valid_rails.size() > 1) + { + bool congestion_fallback = false; + + if (s->params->rail_select == RAIL_DEDICATED) { //then attempt to inject on rail based on the injection queue from the workload + Connection specific_injection_conn = s->connMan.get_connection_on_port(msg->rail_id, true); + if (specific_injection_conn.port == - 1) + tw_error(TW_LOC, "Packet Generation Failure: No connection on specified rail\n"); + if (specific_injection_conn.is_failed) + congestion_fallback = true; + else + { + target_rail_connection = specific_injection_conn; + } + + } + + if (s->params->rail_select == RAIL_PATH) { + int path_lens[valid_rails.size()]; + int min_len = 99999; + int path_tie = 0; + int index = 0; + vector< Connection >::iterator it = valid_rails.begin(); + for(; it != valid_rails.end(); it++) + { + int rail_id = it->rail_or_planar_id; + int dest_router_id = dfdally_get_assigned_router_id_from_terminal(s->params, msg->dfdally_dest_terminal_id, rail_id); + int src_router_id = dfdally_get_assigned_router_id_from_terminal(s->params, s->terminal_id, rail_id); + + path_lens[index] = netMan.get_shortest_dist_between_routers(src_router_id, dest_router_id); + if (path_lens[index] < min_len) { + min_len = path_lens[index]; + target_rail_connection = *it; + tied_rails.clear(); + tied_rails.push_back(*it); + path_tie = 0; + } + else if (path_lens[rail_id] == min_len) + { + path_tie = 1; + tied_rails.push_back(*it); + } + index++; + } + + if(path_tie == 1) + { + int rand_sel = tw_rand_integer(lp->rng, 0, tied_rails.size()-1); + msg->num_rngs++; + target_rail_connection = tied_rails[rand_sel]; + } + } + + if(s->params->rail_select == RAIL_RAND) { + int target_rail_sel = tw_rand_integer(lp->rng, 0, valid_rails.size()-1); + target_rail_connection = valid_rails[target_rail_sel]; + msg->num_rngs++; + } + + if(s->params->rail_select == RAIL_CONGESTION || congestion_fallback) { + int min_score = INT_MAX; + int path_tie = 0; + + vector::iterator it = valid_rails.begin(); + for(; it != valid_rails.end(); it++) + { + int sum = 0; + for(int j = 0; j < p->num_qos_levels; j++) + { + int port_no = it->port; + sum += s->vc_occupancy[port_no][j]; + } + if (sum < min_score) { + min_score = sum; + target_rail_connection = *it; + tied_rails.clear(); + tied_rails.push_back(*it); + path_tie = 0; + } + else if (sum == min_score) + { + path_tie = 1; + tied_rails.push_back(*it); + } + } + if (path_tie == 1) + { + int rand_sel = tw_rand_integer(lp->rng, 0, tied_rails.size() -1); + msg->num_rngs++; + target_rail_connection = tied_rails[rand_sel]; + } + } + } + msg->rail_id = target_rail_connection.rail_or_planar_id; + + dest_router_id = dfdally_get_assigned_router_id_from_terminal(p, msg->dfdally_dest_terminal_id, msg->rail_id); + } else { + dest_router_id = dfdally_get_assigned_router_id_from_terminal(p, msg->dfdally_dest_terminal_id, 0); + } + int dest_grp_id = dest_router_id / s->params->num_routers; + int src_grp_id = s->router_id[msg->rail_id] / s->params->num_routers; if(src_grp_id == dest_grp_id) { - if(dest_router_id == s->router_id) + if(dest_router_id == s->router_id[msg->rail_id]) { bf->c2 = 1; num_local_packets_sr++; @@ -2632,21 +3458,45 @@ static void packet_generate(terminal_state * s, tw_bf * bf, terminal_dally_messa bf->c4 = 1; num_remote_packets++; } - msg->num_rngs++; - nic_ts = g_tw_lookahead + (num_chunks * cn_delay) + tw_rand_unif(lp->rng); msg->packet_ID = s->packet_counter; s->packet_counter++; msg->my_N_hop = 0; msg->my_l_hop = 0; msg->my_g_hop = 0; + msg->my_hops_cur_group = 0; + + + //qos stuff + int num_qos_levels = s->params->num_qos_levels; + int vcg = 0; + + if(num_qos_levels > 1) + { + if(s->is_monitoring_bw == 0) + { + bf->c1 = 1; + /* Issue an event on both terminal and router to monitor bandwidth */ + tw_stime bw_ts = bw_reset_window + gen_noise(lp, &msg->num_rngs); + terminal_dally_message * m; + tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, DRAGONFLY_DALLY, + (void**)&m, NULL); + m->type = T_BANDWIDTH; + m->magic = terminal_magic_num; + s->is_monitoring_bw = 1; + tw_event_send(e); + } + vcg = get_vcg_from_category(msg); + assert(vcg == Q_HIGH || vcg == Q_MEDIUM); + } + assert(vcg < num_qos_levels); for(int i = 0; i < num_chunks; i++) { terminal_dally_message_list *cur_chunk = (terminal_dally_message_list*)calloc(1, sizeof(terminal_dally_message_list)); - msg->origin_router_id = s->router_id; + msg->origin_router_id = s->router_id[msg->rail_id]; init_terminal_dally_message_list(cur_chunk, msg); if(msg->remote_event_size_bytes + msg->local_event_size_bytes > 0) { @@ -2664,41 +3514,97 @@ static void packet_generate(terminal_state * s, tw_bf * bf, terminal_dally_messa m_data_src, msg->local_event_size_bytes); } + cur_chunk->msg.rail_id = msg->rail_id; cur_chunk->msg.output_chan = vcg; cur_chunk->msg.chunk_id = i; - cur_chunk->msg.origin_router_id = s->router_id; - append_to_terminal_dally_message_list(s->terminal_msgs, s->terminal_msgs_tail, + cur_chunk->msg.origin_router_id = s->router_id[msg->rail_id]; + append_to_terminal_dally_message_list(s->terminal_msgs[msg->rail_id], s->terminal_msgs_tail[msg->rail_id], vcg, cur_chunk); - s->terminal_length[vcg] += s->params->chunk_size; + s->terminal_length[msg->rail_id][vcg] += s->params->chunk_size; + } + + double bandwidth_coef = 1; + if (g_congestion_control_enabled) { + if (cc_terminal_is_abatement_active(s->local_congestion_controller)) { + bandwidth_coef = cc_terminal_get_current_injection_bandwidth_coef(s->local_congestion_controller); + } + injection_ts = bytes_to_ns(msg->packet_size, bandwidth_coef * s->params->cn_bandwidth); + } + else { + injection_ts = bytes_to_ns(msg->packet_size, s->params->cn_bandwidth); } + nic_ts = injection_ts; - if(s->terminal_length[vcg] < s->params->cn_vc_size) { - model_net_method_idle_event(nic_ts, 0, lp); - } else { - bf->c11 = 1; - s->issueIdle = 1; - s->stalled_chunks++; - //this block was missing from when QOS was added - readded 5-21-19 - if(s->last_buf_full == 0.0) - { - bf->c8 = 1; - msg->saved_busy_time = s->last_buf_full; - /* TODO: Assumes a single vc from terminal to router */ - s->last_buf_full = tw_now(lp); + + if (s->params->num_injection_queues > 1) { + tw_stime *bts = buff_time_storage_create(s); //mallocs space to push onto the rc stack -- free'd in rc + int *iis = int_storage_create(s); + // int *scs = int_storage_create(s); + + //TODO: Inspect this and verify that we should be looking at each port always + for(int j=0; jparams->num_injection_queues; j++){ + bts[j] = s->last_buf_full[j]; + iis[j] = s->issueIdle[j]; + // scs[j] = s->stalled_chunks[j]; + if(s->terminal_length[j][vcg] < s->params->cn_vc_size && s->issueIdle[j] == 0) + { + model_net_method_idle_event2(nic_ts, 0, j, lp); + } + else + { + s->issueIdle[j] = 1; + // s->stalled_chunks[j]++; + if(s->last_buf_full[j] == 0.0) + { + s->last_buf_full[j] = tw_now(lp);; + } + } + } + rc_stack_push(lp, bts, buff_time_storage_delete, s->st); + rc_stack_push(lp, iis, int_storage_delete, s->st); + // rc_stack_push(lp, scs, int_storage_delete, s->st); + } + else { + if (s->terminal_length[msg->rail_id][vcg] < s->params->cn_vc_size) { + model_net_method_idle_event2(nic_ts, 0, msg->rail_id, lp); + } else { + bf->c11 = 1; + s->issueIdle[msg->rail_id] = 1; + if (s->last_buf_full[msg->rail_id] == 0.0) { + bf->c8 = 1; + msg->saved_busy_time = s->last_buf_full[msg->rail_id]; + s->last_buf_full[msg->rail_id] = tw_now(lp); + } } } + + // if(s->terminal_length[msg->rail_id][vcg] < s->params->cn_vc_size) { + // model_net_method_idle_event2(nic_ts, 0, msg->rail_id, lp); + // } else { + // bf->c11 = 1; + // s->issueIdle[msg->rail_id] = 1; + // s->stalled_chunks[msg->rail_id]++; + + // //this block was missing from when QOS was added - readded 5-21-19 + // if(s->last_buf_full[msg->rail_id] == 0) + // { + // bf->c8 = 1; + // msg->saved_busy_time = s->last_buf_full[msg->rail_id]; + // s->last_buf_full[msg->rail_id] = tw_now(lp); + // } + // } - if(s->in_send_loop == 0) { + if(s->in_send_loop[msg->rail_id] == 0) { bf->c5 = 1; - msg->num_cll++; - ts = codes_local_latency(lp); + ts = 0; terminal_dally_message *m; - tw_event* e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_DALLY, + tw_event* e = model_net_method_event_new(lp->gid, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY, (void**)&m, NULL); + m->rail_id = msg->rail_id; m->type = T_SEND; m->magic = terminal_magic_num; - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = 1; tw_event_send(e); } @@ -2720,37 +3626,31 @@ static void packet_send_rc(terminal_state * s, tw_bf * bf, terminal_dally_messag int num_qos_levels = s->params->num_qos_levels; if(msg->qos_reset1) - s->qos_status[0] = Q_ACTIVE; + s->qos_status[msg->rail_id][0] = Q_ACTIVE; if(msg->qos_reset2) - s->qos_status[1] = Q_ACTIVE; + s->qos_status[msg->rail_id][1] = Q_ACTIVE; if(msg->last_saved_qos) - s->last_qos_lvl = msg->last_saved_qos; + s->last_qos_lvl[msg->rail_id] = msg->last_saved_qos; if(bf->c1) { - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = msg->saved_send_loop; + s->stalled_chunks[msg->rail_id]--; if(bf->c3) - s->last_buf_full = msg->saved_busy_time; + s->last_buf_full[msg->rail_id] = msg->saved_busy_time; return; } int vcg = msg->saved_vc; - s->terminal_available_time = msg->saved_available_time; - - for(int i = 0; i < msg->num_cll; i++) - { - codes_local_latency_reverse(lp); - } + s->terminal_available_time[msg->rail_id] = msg->saved_available_time; - for(int i = 0; i < msg->num_rngs; i++) - { - tw_rand_reverse_unif(lp->rng); - } - s->terminal_length[vcg] += s->params->chunk_size; + s->terminal_length[msg->rail_id][vcg] += s->params->chunk_size; /*TODO: MM change this to the vcg */ - s->vc_occupancy[vcg] -= s->params->chunk_size; - s->link_traffic-=s->params->chunk_size; + s->vc_occupancy[msg->rail_id][vcg] -= s->params->chunk_size; + s->link_traffic[msg->rail_id]-=s->params->chunk_size; + s->total_chunks[msg->rail_id]--; + s->injected_chunks--; terminal_dally_message_list* cur_entry = (terminal_dally_message_list *)rc_stack_pop(s->st); @@ -2758,23 +3658,24 @@ static void packet_send_rc(terminal_state * s, tw_bf * bf, terminal_dally_messag if(cur_entry->msg.packet_size < s->params->chunk_size) data_size = cur_entry->msg.packet_size % s->params->chunk_size; - s->qos_data[vcg] -= data_size; + s->qos_data[msg->rail_id][vcg] -= data_size; - prepend_to_terminal_dally_message_list(s->terminal_msgs, - s->terminal_msgs_tail, vcg, cur_entry); + prepend_to_terminal_dally_message_list(s->terminal_msgs[msg->rail_id], + s->terminal_msgs_tail[msg->rail_id], vcg, cur_entry); + if(bf->c4) { - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = msg->saved_send_loop; } if(bf->c5) { - s->issueIdle = 1; + s->issueIdle[msg->rail_id] = 1; if(bf->c6) { - s->busy_time = msg->saved_total_time; - s->last_buf_full = msg->saved_busy_time; - s->busy_time_sample = msg->saved_sample_time; - s->ross_sample.busy_time_sample = msg->saved_sample_time; - s->busy_time_ross_sample = msg->saved_busy_time_ross; + s->busy_time[msg->rail_id] = msg->saved_total_time; + s->last_buf_full[msg->rail_id] = msg->saved_busy_time; + s->busy_time_sample[msg->rail_id] = msg->saved_sample_time; + s->ross_sample.busy_time_sample[msg->rail_id] = msg->saved_sample_time; + s->busy_time_ross_sample[msg->rail_id] = msg->saved_busy_time_ross; } } return; @@ -2793,8 +3694,7 @@ static void packet_send(terminal_state * s, tw_bf * bf, terminal_dally_message * msg->last_saved_qos = -1; msg->qos_reset1 = -1; msg->qos_reset2 = -1; - msg->num_rngs = 0; - msg->num_cll = 0; + msg->saved_send_loop = s->in_send_loop[msg->rail_id]; vcg = get_next_vcg(s, bf, msg, lp); @@ -2803,51 +3703,66 @@ static void packet_send(terminal_state * s, tw_bf * bf, terminal_dally_message * if(vcg == -1) { bf->c1 = 1; - s->in_send_loop = 0; - if(!s->last_buf_full) + s->in_send_loop[msg->rail_id] = 0; + s->stalled_chunks[msg->rail_id]++; + if(!s->last_buf_full[msg->rail_id]) { bf->c3 = 1; - msg->saved_busy_time = s->last_buf_full; - s->last_buf_full = tw_now(lp); + msg->saved_busy_time = s->last_buf_full[msg->rail_id]; + s->last_buf_full[msg->rail_id] = tw_now(lp); } return; } msg->saved_vc = vcg; - terminal_dally_message_list* cur_entry = s->terminal_msgs[vcg]; + terminal_dally_message_list* cur_entry = s->terminal_msgs[msg->rail_id][vcg]; int data_size = s->params->chunk_size; uint64_t num_chunks = cur_entry->msg.packet_size/s->params->chunk_size; if(cur_entry->msg.packet_size < s->params->chunk_size) num_chunks++; + cur_entry->msg.travel_start_time = tw_now(lp); + + double bandwidth_coef = 1; + if (g_congestion_control_enabled) { + if(cc_terminal_is_abatement_active(s->local_congestion_controller)) { + bandwidth_coef = cc_terminal_get_current_injection_bandwidth_coef(s->local_congestion_controller); + } + } + /* Injection (or transmission) delay: Time taken for the data to be placed on the link/channel + * - Based on bandwidth + * Propagtion delay: Time taken for the data to cross the link and arrive at the reciever + * - A physical property of the material of the link (eg. copper, optical fiber) + */ + tw_stime injection_ts, injection_delay; + tw_stime propagation_ts, propagation_delay; - tw_stime delay = s->params->cn_delay; + double bandwidth = s->params->cn_bandwidth; + if (g_congestion_control_enabled) + bandwidth = bandwidth_coef * bandwidth; + + injection_delay = bytes_to_ns(s->params->chunk_size, bandwidth); if((cur_entry->msg.packet_size < s->params->chunk_size) && (cur_entry->msg.chunk_id == num_chunks - 1)) { data_size = cur_entry->msg.packet_size % s->params->chunk_size; - delay = bytes_to_ns(cur_entry->msg.packet_size % s->params->chunk_size, s->params->cn_bandwidth); + injection_delay = bytes_to_ns(data_size, bandwidth); } + propagation_delay = s->params->cn_delay; - s->qos_data[vcg] += data_size; + s->qos_data[msg->rail_id][vcg] += data_size; - msg->saved_available_time = s->terminal_available_time; + // injection_delay += g_tw_lookahead; - msg->num_rngs++; - ts = g_tw_lookahead + delay + tw_rand_unif(lp->rng); - - s->terminal_available_time = maxd(s->terminal_available_time, tw_now(lp)); - s->terminal_available_time += ts; + msg->saved_available_time = s->terminal_available_time[msg->rail_id]; + s->terminal_available_time[msg->rail_id] = maxd(s->terminal_available_time[msg->rail_id], tw_now(lp)); + s->terminal_available_time[msg->rail_id] += injection_delay; - ts = s->terminal_available_time - tw_now(lp); - codes_mapping_get_lp_info(lp->gid, lp_group_name, &mapping_grp_id, NULL, - &mapping_type_id, NULL, &mapping_rep_id, &mapping_offset); - codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM_ROUT, NULL, 0, - s->router_id / num_routers_per_mgrp, s->router_id % num_routers_per_mgrp, &router_id); + injection_ts = s->terminal_available_time[msg->rail_id] - tw_now(lp); + propagation_ts = injection_ts + propagation_delay; + + router_id = s->router_lp[msg->rail_id]; - // if(s->router_id == 1) - // printf("\n Local router id %d global router id %d ", s->router_id, router_id); - // we are sending an event to the router, so no method_event here void * remote_event; - e = model_net_method_event_new(router_id, ts, lp, + e = model_net_method_event_new(router_id, propagation_ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&m, &remote_event); memcpy(m, &cur_entry->msg, sizeof(terminal_dally_message)); if (m->remote_event_size_bytes){ @@ -2856,6 +3771,8 @@ static void packet_send(terminal_state * s, tw_bf * bf, terminal_dally_message * m->type = R_ARRIVE; m->src_terminal_id = lp->gid; + m->dfdally_src_terminal_id = s->terminal_id; + m->rail_id = msg->rail_id; m->vc_index = vcg; m->last_hop = TERMINAL; m->magic = router_magic_num; @@ -2870,12 +3787,11 @@ static void packet_send(terminal_state * s, tw_bf * bf, terminal_dally_message * if(cur_entry->msg.packet_ID == LLU(TRACK_PKT) && lp->gid == T_ID) printf("\n Packet %llu generated at terminal %d dest %llu size %llu num chunks %llu router-id %d %llu", cur_entry->msg.packet_ID, s->terminal_id, LLU(cur_entry->msg.dest_terminal_lpid), - LLU(cur_entry->msg.packet_size), LLU(num_chunks), s->router_id, LLU(router_id)); + LLU(cur_entry->msg.packet_size), LLU(num_chunks), s->router_id[msg->rail_id], LLU(router_id)); if(cur_entry->msg.chunk_id == num_chunks - 1 && (cur_entry->msg.local_event_size_bytes > 0)) { - msg->num_cll++; - tw_stime local_ts = codes_local_latency(lp); + tw_stime local_ts = 0; tw_event *e_new = tw_event_new(cur_entry->msg.sender_lp, local_ts, lp); void * m_new = tw_event_data(e_new); void *local_event = (char*)cur_entry->event_data + @@ -2884,11 +3800,13 @@ static void packet_send(terminal_state * s, tw_bf * bf, terminal_dally_message * tw_event_send(e_new); } - s->vc_occupancy[vcg] += s->params->chunk_size; - cur_entry = return_head(s->terminal_msgs, s->terminal_msgs_tail, vcg); + s->vc_occupancy[msg->rail_id][vcg] += s->params->chunk_size; + cur_entry = return_head(s->terminal_msgs[msg->rail_id], s->terminal_msgs_tail[msg->rail_id], vcg); rc_stack_push(lp, cur_entry, delete_terminal_dally_message_list, s->st); - s->terminal_length[vcg] -= s->params->chunk_size; - s->link_traffic += s->params->chunk_size; + s->terminal_length[msg->rail_id][vcg] -= s->params->chunk_size; + s->link_traffic[msg->rail_id] += s->params->chunk_size; + s->total_chunks[msg->rail_id]++; + s->injected_chunks++; //TODO: if a terminal can inject packets from multiple jobs, it might be beneficial to make that matter here int next_vcg = 0; @@ -2897,42 +3815,39 @@ static void packet_send(terminal_state * s, tw_bf * bf, terminal_dally_message * cur_entry = NULL; if(next_vcg >= 0) - cur_entry = s->terminal_msgs[next_vcg]; + cur_entry = s->terminal_msgs[msg->rail_id][next_vcg]; /* if there is another packet inline then schedule another send event */ - if(cur_entry != NULL && s->vc_occupancy[next_vcg] + s->params->chunk_size <= s->params->cn_vc_size) { + if(cur_entry != NULL && s->vc_occupancy[msg->rail_id][next_vcg] + s->params->chunk_size <= s->params->cn_vc_size) { terminal_dally_message *m_new; - msg->num_rngs++; - ts += tw_rand_unif(lp->rng); - e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_DALLY, (void**)&m_new, NULL); + e = model_net_method_event_new(lp->gid, injection_ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY, (void**)&m_new, NULL); m_new->type = T_SEND; + m_new->rail_id = msg->rail_id; m_new->magic = terminal_magic_num; tw_event_send(e); } else { /* If not then the LP will wait for another credit or packet generation */ bf->c4 = 1; - s->in_send_loop = 0; + s->in_send_loop[msg->rail_id] = 0; } - if(s->issueIdle) { + if(s->issueIdle[msg->rail_id]) { bf->c5 = 1; - s->issueIdle = 0; - msg->num_rngs++; - ts += tw_rand_unif(lp->rng); - model_net_method_idle_event(ts, 0, lp); + s->issueIdle[msg->rail_id] = 0; + model_net_method_idle_event2(injection_ts, 0, msg->rail_id, lp); - if(s->last_buf_full > 0.0) + if(s->last_buf_full[msg->rail_id] > 0.0) { bf->c6 = 1; - msg->saved_total_time = s->busy_time; - msg->saved_busy_time = s->last_buf_full; - msg->saved_sample_time = s->busy_time_sample; - - s->busy_time += (tw_now(lp) - s->last_buf_full); - s->busy_time_sample += (tw_now(lp) - s->last_buf_full); - s->ross_sample.busy_time_sample += (tw_now(lp) - s->last_buf_full); - msg->saved_busy_time_ross = s->busy_time_ross_sample; - s->busy_time_ross_sample += (tw_now(lp) - s->last_buf_full); - s->last_buf_full = 0.0; + msg->saved_total_time = s->busy_time[msg->rail_id]; + msg->saved_busy_time = s->last_buf_full[msg->rail_id]; + msg->saved_sample_time = s->busy_time_sample[msg->rail_id]; + + s->busy_time[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + s->busy_time_sample[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + s->ross_sample.busy_time_sample[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + msg->saved_busy_time_ross = s->busy_time_ross_sample[msg->rail_id]; + s->busy_time_ross_sample[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + s->last_buf_full[msg->rail_id] = 0.0; } } return; @@ -2943,8 +3858,7 @@ static void send_remote_event(terminal_state * s, terminal_dally_message * msg, { void * tmp_ptr = model_net_method_get_edata(DRAGONFLY_DALLY, msg); - msg->num_rngs++; - tw_stime ts = g_tw_lookahead + mpi_soft_overhead + tw_rand_unif(lp->rng); + tw_stime ts = 0; if (msg->is_pull){ bf->c4 = 1; @@ -2957,7 +3871,7 @@ static void send_remote_event(terminal_state * s, terminal_dally_message * msg, model_net_set_msg_param(MN_MSG_PARAM_START_TIME, MN_MSG_PARAM_START_TIME_VAL, &(msg->msg_start_time)); msg->event_rc = model_net_event_mctx(net_id, &mc_src, &mc_dst, msg->category, - msg->sender_lp, msg->pull_size, ts, + msg->sender_lp, msg->pull_size, ts + gen_noise(lp, &msg->num_rngs), remote_event_size, tmp_ptr, 0, NULL, lp); } else{ @@ -2971,12 +3885,8 @@ static void send_remote_event(terminal_state * s, terminal_dally_message * msg, static void packet_arrive_rc(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { - - for(int i = 0; i < msg->num_rngs; i++) - tw_rand_reverse_unif(lp->rng); - - for(int i = 0; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); + if (g_congestion_control_enabled) + cc_terminal_send_ack_rc(s->local_congestion_controller); if(bf->c31) { @@ -2994,6 +3904,7 @@ static void packet_arrive_rc(terminal_state * s, tw_bf * bf, terminal_dally_mess s->fin_chunks_sample--; s->ross_sample.fin_chunks_sample--; s->fin_chunks_ross_sample--; + s->ejected_chunks--; total_hops -= msg->my_N_hop; s->total_hops -= msg->my_N_hop; @@ -3027,6 +3938,8 @@ static void packet_arrive_rc(terminal_state * s, tw_bf * bf, terminal_dally_mess s->finished_packets--; } + if(bf->c21) + s->min_latency = msg->saved_min_lat; if(bf->c22) { s->max_latency = msg->saved_available_time; @@ -3074,17 +3987,30 @@ static void packet_arrive_rc(terminal_state * s, tw_bf * bf, terminal_dally_mess static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { + // if(isRoutingMinimal(routing) && msg->my_N_hop > 4) + // { + // printf("TERMINAL RECEIVED A NONMINIMAL LENGTH PACKET\n"); + // } + // if(isRoutingMinimal(routing) && msg->my_g_hop > 1) + // { + // printf("TERMINAL RECEIVED A DOUBLE GLOBAL HOP PACKET\n"); + // } + // printf("%d\n",msg->my_g_hop); + if (msg->dfdally_dest_terminal_id != s->terminal_id) + tw_error(TW_LOC, "Packet arrived at wrong terminal\n"); + if (msg->my_N_hop > s->params->max_hops_notify) { printf("Terminal received a packet with %d hops! (Notify on > than %d)\n",msg->my_N_hop, s->params->max_hops_notify); } + + if (g_congestion_control_enabled) + cc_terminal_send_ack(s->local_congestion_controller, msg->src_terminal_id); + // NIC aggregation - should this be a separate function? // Trigger an event on receiving server - msg->num_rngs = 0; - msg->num_cll = 0; - if(!s->rank_tbl) s->rank_tbl = qhash_init(dragonfly_rank_hash_compare, dragonfly_hash_func, DFLY_HASH_TABLE_SIZE); @@ -3122,15 +4048,15 @@ static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message if(msg->packet_ID == LLU(TRACK_PKT) && msg->src_terminal_id == T_ID) printf("\n Packet %llu arrived at lp %llu hops %d ", LLU(msg->sender_lp), LLU(lp->gid), msg->my_N_hop); - msg->num_rngs++; - tw_stime ts = g_tw_lookahead + s->params->cn_credit_delay + tw_rand_unif(lp->rng); + tw_stime ts = s->params->cn_credit_delay; // no method_event here - message going to router tw_event * buf_e; terminal_dally_message * buf_msg; - buf_e = model_net_method_event_new(msg->intm_lp_id, ts, lp, + buf_e = model_net_method_event_new(msg->intm_lp_id, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&buf_msg, NULL); buf_msg->magic = router_magic_num; + buf_msg->rail_id = msg->rail_id; buf_msg->vc_index = msg->vc_index; buf_msg->output_chan = msg->output_chan; buf_msg->type = R_BUFFER; @@ -3149,6 +4075,7 @@ static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message s->fin_chunks_sample++; s->ross_sample.fin_chunks_sample++; s->fin_chunks_ross_sample++; + s->ejected_chunks++; /* WE do not allow self messages through dragonfly */ assert(lp->gid != msg->src_terminal_id); @@ -3158,7 +4085,7 @@ static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message num_chunks++; if(msg->path_type == MINIMAL) - minimal_count++; + minimal_count++; if(msg->path_type == NON_MINIMAL) nonmin_count++; @@ -3172,16 +4099,20 @@ static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message if(msg->path_type != MINIMAL && msg->path_type != NON_MINIMAL) printf("\n Wrong message path type %d ", msg->path_type); + //record for commit_f file IO + msg->travel_end_time = tw_now(lp); + tw_stime ete_latency = msg->travel_end_time - msg->travel_start_time; + /* save the sample time */ msg->saved_sample_time = s->fin_chunks_time; - s->fin_chunks_time += (tw_now(lp) - msg->travel_start_time); - s->ross_sample.fin_chunks_time += (tw_now(lp) - msg->travel_start_time); + s->fin_chunks_time += ete_latency; + s->ross_sample.fin_chunks_time += ete_latency; msg->saved_fin_chunks_ross = s->fin_chunks_time_ross_sample; - s->fin_chunks_time_ross_sample += (tw_now(lp) - msg->travel_start_time); + s->fin_chunks_time_ross_sample += ete_latency; /* save the total time per LP */ msg->saved_avg_time = s->total_time; - s->total_time += (tw_now(lp) - msg->travel_start_time); + s->total_time += ete_latency; total_hops += msg->my_N_hop; s->total_hops += msg->my_N_hop; s->fin_hops_sample += msg->my_N_hop; @@ -3190,7 +4121,7 @@ static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message mn_stats* stat = model_net_find_stats(msg->category, s->dragonfly_stats_array); msg->saved_rcv_time = stat->recv_time; - stat->recv_time += (tw_now(lp) - msg->travel_start_time); + stat->recv_time += ete_latency; #if DEBUG == 1 if( msg->packet_ID == TRACK @@ -3253,14 +4184,16 @@ static void packet_arrive(terminal_state * s, tw_bf * bf, terminal_dally_message memcpy(tmp->remote_event_data, m_data_src, msg->remote_event_size_bytes); } - if(s->min_latency > tw_now(lp) - msg->travel_start_time) { - s->min_latency = tw_now(lp) - msg->travel_start_time; + if(s->min_latency > ete_latency) { + bf->c21 = 1; + msg->saved_min_lat = s->min_latency; + s->min_latency = ete_latency; } - if(s->max_latency < tw_now( lp ) - msg->travel_start_time) { + if(s->max_latency < ete_latency) { bf->c22 = 1; msg->saved_available_time = s->max_latency; - s->max_latency = tw_now(lp) - msg->travel_start_time; + s->max_latency = ete_latency; } /* If all chunks of a message have arrived then send a remote event to the * callee*/ @@ -3298,15 +4231,12 @@ static void terminal_buf_update_rc(terminal_state * s, int vcg = 0; int num_qos_levels = s->params->num_qos_levels; - for(int i = 0; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - if(num_qos_levels > 1) vcg = get_vcg_from_category(msg); - s->vc_occupancy[vcg] += s->params->chunk_size; + s->vc_occupancy[msg->rail_id][vcg] += s->params->chunk_size; if(bf->c1) { - s->in_send_loop = 0; + s->in_send_loop[msg->rail_id] = 0; } return; @@ -3317,9 +4247,6 @@ static void terminal_buf_update(terminal_state * s, terminal_dally_message * msg, tw_lp * lp) { - msg->num_cll = 0; - msg->num_rngs = 0; - bf->c1 = 0; bf->c2 = 0; bf->c3 = 0; @@ -3330,18 +4257,18 @@ static void terminal_buf_update(terminal_state * s, if(num_qos_levels > 1) vcg = get_vcg_from_category(msg); - msg->num_cll++; - tw_stime ts = codes_local_latency(lp); - s->vc_occupancy[vcg] -= s->params->chunk_size; + tw_stime ts = 0; + s->vc_occupancy[msg->rail_id][vcg] -= s->params->chunk_size; - if(s->in_send_loop == 0 && s->terminal_msgs[vcg] != NULL) { + if(s->in_send_loop[msg->rail_id] == 0 && s->terminal_msgs[msg->rail_id][vcg] != NULL) { terminal_dally_message *m; bf->c1 = 1; - tw_event* e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_DALLY, + tw_event* e = model_net_method_event_new(lp->gid, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY, (void**)&m, NULL); + m->rail_id = msg->rail_id; m->type = T_SEND; m->magic = terminal_magic_num; - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = 1; tw_event_send(e); } return; @@ -3366,9 +4293,13 @@ dragonfly_dally_terminal_final( terminal_state * s, written += sprintf(s->output_buf + written, "# Format < dest_type> \n"); // fprintf(fp, "# Format <# Flits/Packets finished> \n"); } - //since LLU(s->total_msg_size) is total message size a terminal received from a router so source is router and destination is terminal - written += sprintf(s->output_buf + written, "\n%u %s %u %s %s %llu %lf %lu", - s->terminal_id, "T",s->router_id, "R","CN", LLU(s->link_traffic), s->busy_time, s->stalled_chunks); + for(int i = 0; i < s->params->num_rails; i++) + { + //since LLU(s->total_msg_size) is total message size a terminal received from a router so source is router and destination is terminal + written += sprintf(s->output_buf + written, "\n%u %s %u %s %s %llu %lf %lu", + s->terminal_id, "T",s->router_id[i], "R","CN", LLU(s->link_traffic[i]), s->busy_time[i], s->stalled_chunks[i]); + } + lp_io_write(lp->gid, (char*)"dragonfly-link-stats", written, s->output_buf); @@ -3388,14 +4319,26 @@ dragonfly_dally_terminal_final( terminal_state * s, written = 0; if(s->terminal_id == 0) { - written += sprintf(s->output_buf2 + written, "# Format <# Packets finished> \n"); + written += sprintf(s->output_buf2 + written, "# Format <# Packets finished> \n"); } + + tw_stime avg_busy_time = 0; + for(int i = 0; i < s->params->num_rails; i++) + avg_busy_time += s->busy_time[i]; + avg_busy_time = avg_busy_time / s->params->num_rails; + + written += sprintf(s->output_buf2 + written, "%llu %u %d %llu %lf %lf %lf %ld %lf %lf\n", LLU(lp->gid), s->terminal_id, s->total_gen_size, LLU(s->total_msg_size), s->total_time/s->finished_chunks, s->max_latency, s->min_latency, - s->finished_packets, (double)s->total_hops/s->finished_chunks, s->busy_time); + s->finished_packets, (double)s->total_hops/s->finished_chunks, avg_busy_time); + + for(int i = 0; i < s->params->num_rails; i++) + { + if(s->terminal_msgs[i][0] != NULL) + printf("[%llu] leftover terminal messages \n", LLU(lp->gid)); + } + - if(s->terminal_msgs[0] != NULL) - printf("[%llu] leftover terminal messages \n", LLU(lp->gid)); lp_io_write(lp->gid, (char*)"dragonfly-cn-stats", written, s->output_buf2); @@ -3406,13 +4349,32 @@ dragonfly_dally_terminal_final( terminal_state * s, qhash_finalize(s->rank_tbl); rc_stack_destroy(s->st); + //TODO FREE THESE CORRECTLY + for(int i = 0; i < s->params->num_rails; i++) + { + free(s->vc_occupancy[i]); + free(s->terminal_msgs[i]); + free(s->terminal_msgs_tail[i]); + } free(s->vc_occupancy); free(s->terminal_msgs); free(s->terminal_msgs_tail); } -void dragonfly_dally_router_final(router_state * s, tw_lp * lp) -{ +void dragonfly_dally_router_final(router_state * s, tw_lp * lp){ + + unsigned long total_stalled_chunks = 0; + unsigned long total_total_chunks = 0; + for (int i = 0; i < s->params->radix; i++) + { + total_stalled_chunks += s->stalled_chunks[i]; + total_total_chunks += s->total_chunks[i]; + } + // printf("%d: %.5f\n",s->router_id, s->last_time); + global_stalled_chunk_counter += total_stalled_chunks; + + // printf("%lu: stalled chunks %lu total_chunks %lu\n", lp->gid, total_stalled_chunks, total_total_chunks); + free(s->global_channel); int i, j; for(i = 0; i < s->params->radix; i++) { @@ -3427,7 +4389,7 @@ void dragonfly_dally_router_final(router_state * s, tw_lp * lp) } } - if(s->router_id == 0) + if(s->router_id == 0 && ROUTER_BW_LOG) fclose(dragonfly_rtr_bw_log); rc_stack_destroy(s->st); @@ -3453,7 +4415,7 @@ void dragonfly_dally_router_final(router_state * s, tw_lp * lp) } } - vector< Connection > my_global_links = s->connMan->get_connections_by_type(CONN_GLOBAL); + vector< Connection > my_global_links = s->connMan.get_connections_by_type(CONN_GLOBAL,true); vector< Connection >::iterator it = my_global_links.begin(); for(; it != my_global_links.end(); it++) { @@ -3471,7 +4433,7 @@ void dragonfly_dally_router_final(router_state * s, tw_lp * lp) s->stalled_chunks[port_no]); } - vector< Connection > my_terminal_links = s->connMan->get_connections_by_type(CONN_TERMINAL); + vector< Connection > my_terminal_links = s->connMan.get_connections_by_type(CONN_TERMINAL,true); it = my_terminal_links.begin(); for(; it != my_terminal_links.end(); it++) { @@ -3491,6 +4453,9 @@ void dragonfly_dally_router_final(router_state * s, tw_lp * lp) sprintf(s->output_buf + written, "\n"); lp_io_write(lp->gid, (char*)"dragonfly-link-stats", written, s->output_buf); + if(g_congestion_control_enabled) + cc_router_local_controller_finalize(s->local_congestion_controller); + /*if(!s->router_id) { written = sprintf(s->output_buf, "# Format "); @@ -3522,42 +4487,56 @@ static Connection do_dfdally_routing(router_state *s, tw_bf *bf, terminal_dally_ int fdest_group_id = fdest_router_id / s->params->num_routers; int origin_group_id = msg->origin_router_id / s->params->num_routers; - // Legacy progressive adaptive routing has its own ways of doing this. These should probably be moved - // into their own function as "default behavior" that is then called when needed by the other routing - // functions individually. - // TODO: put the local destination group routing into its own function for "default" behavior. - if (routing != PROG_ADAPTIVE_LEGACY) - { - // // Local Destination Group Routing -------------- - if (my_router_id == fdest_router_id) { //destination router reached, next dest = final terminal destination - vector< Connection > poss_next_stops = s->connMan->get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL); - if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "Destination Router %d: No connection to destination terminal %d\n", s->router_id, msg->dfdally_dest_terminal_id); //shouldn't happen unless math was wrong - Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); - return best_min_conn; - } - else if (my_group_id == fdest_group_id) { //Then we're already in the destination group and should just route to the fdest router - vector< Connection > conns_to_fdest = s->connMan->get_connections_to_gid(fdest_router_id, CONN_LOCAL); - if (conns_to_fdest.size() < 1) - tw_error(TW_LOC, "Destination Group %d: No connection to destination router %d\n", s->router_id, fdest_router_id); //shouldn't happen unless the connections weren't set up / loaded correctly - - if (isRoutingAdaptive(routing)) { // Pick the best connection - Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, conns_to_fdest); - return best_conn; + + if (!isRoutingSmart(routing)) + { + // Legacy progressive adaptive routing has its own ways of doing this. These should probably be moved + // into their own function as "default behavior" that is then called when needed by the other routing + // functions individually. + // If link failures are enabled, then this default local destination group routing can't be considered valid + // as it assumes full connectivity in the local groups. + // TODO: put the local destination group routing into its own function for "default" behavior. + // if (routing != PROG_ADAPTIVE_LEGACY && !netMan.is_link_failures_enabled()) //for now when intra and interconnections aren't allowed to be failed, this is OK. + if (routing != PROG_ADAPTIVE_LEGACY) + { + // // Local Destination Group Routing -------------- + if (my_router_id == fdest_router_id) { //destination router reached, next dest = final terminal destination + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No connection to destination terminal %d\n", s->router_id, msg->dfdally_dest_terminal_id); //shouldn't happen unless math was wrong + + Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_min_conn; } - else { //Randomize the next legal stop - msg->num_rngs++; - int rand_sel = tw_rand_integer(lp->rng, 0, conns_to_fdest.size()-1); - Connection next_conn = conns_to_fdest[rand_sel]; - return next_conn; + else if (my_group_id == fdest_group_id) { //Then we're already in the destination group and should just route to the fdest router + vector< Connection > conns_to_fdest = s->connMan.get_connections_to_gid(fdest_router_id, CONN_LOCAL); + if (conns_to_fdest.size() < 1) + { + vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + if(poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Group %d: No connection to destination router %d\n", s->router_id, fdest_router_id); //shouldn't happen unless the connections weren't set up / loaded correctly + conns_to_fdest = poss_next_stops; + } + + + if (isRoutingAdaptive(routing)) { // Pick the best connection + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, conns_to_fdest); + return best_conn; + } + else { //Randomize the next legal stop + msg->num_rngs++; + int rand_sel = tw_rand_integer(lp->rng, 0, conns_to_fdest.size()-1); + Connection next_conn = conns_to_fdest[rand_sel]; + return next_conn; + } } - } - // // End Local Destination Group Routing ------------- + // // End Local Destination Group Routing ------------- - if(msg->last_hop == TERMINAL) //This is used by dfdally_nonminimal_routing and dfdally_prog_adaptive_routing - { - if (msg->intm_grp_id == -1) - dfdally_select_intermediate_group(s, bf, msg, lp, fdest_router_id); + if(msg->last_hop == TERMINAL) //This is used by dfdally_nonminimal_routing and dfdally_prog_adaptive_routing + { + if (msg->intm_grp_id == -1) + dfdally_select_intermediate_group(s, bf, msg, lp, fdest_router_id); + } } } @@ -3580,6 +4559,15 @@ static Connection do_dfdally_routing(router_state *s, tw_bf *bf, terminal_dally_ case PROG_ADAPTIVE_LEGACY: next_stop_conn = dfdally_prog_adaptive_legacy_routing(s, bf, msg, lp, fdest_router_id); break; + case SMART_PROG_ADAPTIVE: + next_stop_conn = dfdally_smart_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); + break; + case SMART_MINIMAL: + next_stop_conn = dfdally_smart_minimal_routing(s, bf, msg, lp, fdest_router_id); + break; + case SMART_NON_MINIMAL: + next_stop_conn = dfdally_smart_nonminimal_routing(s, bf, msg, lp, fdest_router_id); + break; default: tw_error(TW_LOC, "Error: No valid routing algorithm specified"); break; @@ -3609,7 +4597,8 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_dal tw_error(TW_LOC, "\nRouter Receipt Verify: Codes Mapping Get LP Rel ID Failure - Terminal"); } - has_valid_connection = (s->router_id == (src_term_rel_id / s->params->num_cn)); //a router can only receive a packet from a terminal if that terminal belongs to it + // has_valid_connection = (s->router_id == (src_term_rel_id / s->params->num_cn)); //a router can only receive a packet from a terminal if that terminal belongs to it + has_valid_connection = s->connMan.is_connected_to_by_type(src_term_rel_id, CONN_TERMINAL); if (!has_valid_connection) { tw_error(TW_LOC, "\nRouter received packet from non-existent connection - Terminal\n"); @@ -3626,7 +4615,7 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_dal } int rel_loc_id = rel_id % s->params->num_routers; - has_valid_connection = s->connMan->is_connected_to_by_type(rel_loc_id, CONN_LOCAL); + has_valid_connection = s->connMan.is_connected_to_by_type(rel_loc_id, CONN_LOCAL); } else if (msg->last_hop == GLOBAL) { @@ -3636,7 +4625,7 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_dal catch (...) { tw_error(TW_LOC, "\nRouter Receipt Verify: Codes Mapping Get LP Rel ID Failure - Global"); } - has_valid_connection = s->connMan->is_connected_to_by_type(rel_id, CONN_GLOBAL); + has_valid_connection = s->connMan.is_connected_to_by_type(rel_id, CONN_GLOBAL); } else { tw_error(TW_LOC, "\nUnspecified msg->last_hop when received by a router\n"); @@ -3675,20 +4664,24 @@ static void router_credit_send(router_state * s, terminal_dally_message * msg, else printf("\n Invalid message type"); - (*rng_counter)++; - ts = g_tw_lookahead + credit_delay + tw_rand_unif(lp->rng); + /* TODO: Credit delay should really be a combination of credit processing time, + * the injection delay, and propagation delay of the channel. But this level of + * granularity _may_ only be necessary for specific credit-based flow control + * studies. It should certainly be considered for those studies. */ + ts = credit_delay; if (is_terminal) { - buf_e = model_net_method_event_new(dest, ts, lp, DRAGONFLY_DALLY, + buf_e = model_net_method_event_new(dest, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY, (void**)&buf_msg, NULL); buf_msg->magic = terminal_magic_num; } else { - buf_e = model_net_method_event_new(dest, ts, lp, DRAGONFLY_DALLY_ROUTER, + buf_e = model_net_method_event_new(dest, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&buf_msg, NULL); buf_msg->magic = router_magic_num; } + buf_msg->rail_id = msg->rail_id; buf_msg->origin_router_id = s->router_id; if(sq == -1) { buf_msg->vc_index = msg->vc_index; @@ -3711,12 +4704,8 @@ static void router_packet_receive_rc(router_state * s, { int output_port = msg->saved_vc; int output_chan = msg->saved_channel; - - for(int i = 0 ; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - - for(int i = 0; i < msg->num_rngs; i++) - tw_rand_reverse_unif(lp->rng); + int src_term_id = msg->dfdally_src_terminal_id; + int app_id = msg->saved_app_id; if(bf->c1) s->is_monitoring_bw = 0; @@ -3739,6 +4728,12 @@ static void router_packet_receive_rc(router_state * s, s->queued_msgs_tail[output_port], output_chan)); s->queued_count[output_port] -= s->params->chunk_size; } + + if (g_congestion_control_enabled) { + congestion_control_message *cc_msg_rc = (congestion_control_message*)rc_stack_pop(s->cc_st); + cc_router_received_packet_rc(s->local_congestion_controller, lp, s->params->chunk_size, output_port, output_chan, src_term_id, app_id, cc_msg_rc); + cc_msg_rc_storage_delete(cc_msg_rc); + } } /* Packet arrives at the router and a credit is sent back to the sending terminal/router */ @@ -3747,9 +4742,6 @@ static void router_packet_receive( router_state * s, terminal_dally_message * msg, tw_lp * lp ) { - msg->num_cll = 0; - msg->num_rngs = 0; - router_verify_valid_receipt(s, bf, msg, lp); tw_stime ts; @@ -3762,10 +4754,9 @@ static void router_packet_receive( router_state * s, if(s->is_monitoring_bw == 0) { bf->c1 = 1; - msg->num_cll++; - tw_stime bw_ts = bw_reset_window + codes_local_latency(lp); + tw_stime bw_ts = bw_reset_window; terminal_dally_message * m; - tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, + tw_event * e = model_net_method_event_new(lp->gid, bw_ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&m, NULL); m->type = R_BANDWIDTH; m->magic = router_magic_num; @@ -3782,18 +4773,23 @@ static void router_packet_receive( router_state * s, int total_routers = s->params->total_routers; int next_stop = -1, output_port = -1, output_chan = -1; - int dest_router_id = codes_mapping_get_lp_relative_id(msg->dest_terminal_lpid, 0, 0) / s->params->num_cn; + int dest_router_id = dfdally_get_assigned_router_id_from_terminal(s->params, msg->dfdally_dest_terminal_id, s->plane_id); + // int dest_router_id = codes_mapping_get_lp_relative_id(msg->dest_terminal_lpid, 0, 0) / s->params->num_cn; + msg->this_router_arrival = tw_now(lp); terminal_dally_message_list * cur_chunk = (terminal_dally_message_list*)calloc(1, sizeof(terminal_dally_message_list)); init_terminal_dally_message_list(cur_chunk, msg); if(cur_chunk->msg.last_hop == TERMINAL) // We are first router in the path cur_chunk->msg.path_type = MINIMAL; // Route always starts as minimal + + int num_rngs_before = (cur_chunk->msg).num_rngs; Connection next_stop_conn = do_dfdally_routing(s, bf, &(cur_chunk->msg), lp, dest_router_id); - msg->num_rngs += (cur_chunk->msg).num_rngs; //make sure we're counting the rngs called during do_dfdally_routing() + msg->num_rngs += (cur_chunk->msg).num_rngs - num_rngs_before; //make sure we're counting the rngs called during do_dfdally_routing() + cur_chunk->msg.num_rngs = num_rngs_before; - if (s->connMan->is_any_connection_to(next_stop_conn.dest_gid) == false) + if (s->connMan.is_any_connection_to(next_stop_conn.dest_gid) == false) tw_error(TW_LOC, "Router %d does not have a connection to chosen destination %d\n", s->router_id, next_stop_conn.dest_gid); output_port = next_stop_conn.port; @@ -3815,31 +4811,67 @@ static void router_packet_receive( router_state * s, // printf("Router %d: Output Port = %d next stop = %d\n",s->router_id, output_port, next_stop); - //TODO double check the dfdally vc selection process int max_vc_size = s->params->cn_vc_size; + int my_group_id = s->group_id; + int src_group_id = msg->origin_router_id / num_routers; + int dest_group_id = dest_router_id / num_routers; + output_chan = 0; - if(output_port < s->params->intra_grp_radix) { - if(cur_chunk->msg.my_g_hop == 1 && cur_chunk->msg.last_hop == GLOBAL) { + if (my_group_id == src_group_id) + { + output_chan = cur_chunk->msg.my_l_hop; + if(msg->path_type == NON_MINIMAL) output_chan = 1; - } - else if(cur_chunk->msg.my_g_hop == 1 && cur_chunk->msg.last_hop == LOCAL) { - output_chan = 2; - } - else if (cur_chunk->msg.my_g_hop == 2) { - output_chan = 3; - } - + } + else if (my_group_id != src_group_id && my_group_id != dest_group_id) + { + assert(msg->path_type == NON_MINIMAL); + output_chan = 2; + } + else if (my_group_id == dest_group_id) + { + output_chan = 3; + } + + if (next_stop_conn.conn_type == CONN_LOCAL) + { max_vc_size = s->params->local_vc_size; cur_chunk->msg.my_l_hop++; - } - else if(output_port < (s->params->intra_grp_radix + - s->params->num_global_channels)) + cur_chunk->msg.my_hops_cur_group++; + } + if (next_stop_conn.conn_type == CONN_GLOBAL) { - output_chan = cur_chunk->msg.my_g_hop; max_vc_size = s->params->global_vc_size; + cur_chunk->msg.my_hops_cur_group = 0; //reset this as it's going to a new group cur_chunk->msg.my_g_hop++; } + + //this seemed outdated with current literature and was replaced with the scheme above. + // output_chan = 0; + // if(output_port < s->params->intra_grp_radix) { + // if(cur_chunk->msg.my_g_hop == 1 && cur_chunk->msg.last_hop == GLOBAL) { + // output_chan = 1; + // } + // else if(cur_chunk->msg.my_g_hop == 1 && cur_chunk->msg.last_hop == LOCAL) { + // output_chan = 2; + // } + // else if (cur_chunk->msg.my_g_hop == 2) { + // output_chan = 3; + // } + + // max_vc_size = s->params->local_vc_size; + // cur_chunk->msg.my_l_hop++; + // cur_chunk->msg.my_hops_cur_group++; + // } + // else if(output_port < (s->params->intra_grp_radix + + // s->params->num_global_channels)) + // { + // output_chan = cur_chunk->msg.my_g_hop; + // max_vc_size = s->params->global_vc_size; + // cur_chunk->msg.my_hops_cur_group = 0; //reset this as it's going to a new group + // cur_chunk->msg.my_g_hop++; + // } assert(output_chan < vcs_per_qos); output_chan = output_chan + (vcg * vcs_per_qos); @@ -3875,10 +4907,10 @@ static void router_packet_receive( router_state * s, if(s->in_send_loop[output_port] == 0) { bf->c3 = 1; terminal_dally_message *m; - msg->num_cll++; - ts = codes_local_latency(lp); - tw_event *e = model_net_method_event_new(lp->gid, ts, lp, + ts = maxd(s->next_output_available_time[output_port], tw_now(lp)) - tw_now(lp); + tw_event *e = model_net_method_event_new(lp->gid, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&m, NULL); + m->rail_id = msg->rail_id; m->type = R_SEND; m->magic = router_magic_num; m->vc_index = output_port; @@ -3904,7 +4936,7 @@ static void router_packet_receive( router_state * s, * that is empty then we check if last_buf_full is set or not. If already * set then we don't overwrite it. If two packets arrive next to each other * then the first person should be setting it. */ - if(s->pending_msgs[output_port][output_chan] == NULL && s->last_buf_full[output_port] == 0.0) + if(s->last_buf_full[output_port] == 0.0) { bf->c22 = 1; msg->saved_busy_time = s->last_buf_full[output_port]; @@ -3912,6 +4944,14 @@ static void router_packet_receive( router_state * s, } } + if (g_congestion_control_enabled) { + congestion_control_message *cc_msg_rc = cc_msg_rc_storage_create(); + cc_router_received_packet(s->local_congestion_controller, lp, s->params->chunk_size, output_port, output_chan, cur_chunk->msg.dfdally_src_terminal_id, cur_chunk->msg.app_id, cc_msg_rc); + rc_stack_push(lp, cc_msg_rc, cc_msg_rc_storage_delete, s->cc_st); + } + + msg->saved_app_id = cur_chunk->msg.app_id; + msg->dfdally_src_terminal_id = cur_chunk->msg.dfdally_src_terminal_id; msg->saved_vc = output_port; msg->saved_channel = output_chan; return; @@ -3922,6 +4962,8 @@ static void router_packet_send_rc(router_state * s, tw_bf * bf, terminal_dally_m int num_qos_levels = s->params->num_qos_levels; int output_port = msg->saved_vc; + int src_term_id = msg->dfdally_src_terminal_id; + int app_id = msg->saved_app_id; if(msg->qos_reset1) s->qos_status[output_port][0] = Q_ACTIVE; @@ -3932,19 +4974,13 @@ static void router_packet_send_rc(router_state * s, tw_bf * bf, terminal_dally_m s->last_qos_lvl[output_port] = msg->last_saved_qos; if(bf->c1) { - s->in_send_loop[output_port] = 1; + s->in_send_loop[output_port] = msg->saved_send_loop; if(bf->c2) { s->last_buf_full[output_port] = msg->saved_busy_time; } return; } - - for(int i = 0; i < msg->num_rngs; i++) - tw_rand_reverse_unif(lp->rng); - for(int i = 0; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - int output_chan = msg->saved_channel; if(bf->c8) { @@ -3983,17 +5019,24 @@ static void router_packet_send_rc(router_state * s, tw_bf * bf, terminal_dally_m s->link_traffic_ross_sample[output_port] -= s->params->chunk_size; } + s->total_chunks[output_port]--; + prepend_to_terminal_dally_message_list(s->pending_msgs[output_port], s->pending_msgs_tail[output_port], output_chan, cur_entry); + if (g_congestion_control_enabled) { + congestion_control_message *cc_msg_rc = (congestion_control_message*)rc_stack_pop(s->cc_st); + cc_router_forwarded_packet_rc(s->local_congestion_controller, lp, s->params->chunk_size, output_port, output_chan, src_term_id, app_id, cc_msg_rc); + cc_msg_rc_storage_delete(cc_msg_rc); + } + if(bf->c4) { - s->in_send_loop[output_port] = 1; + s->in_send_loop[output_port] = msg->saved_send_loop; } } /* routes the current packet to the next stop */ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { - tw_stime ts; tw_event *e; terminal_dally_message *m; int output_port = msg->vc_index; @@ -4004,8 +5047,7 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes msg->last_saved_qos = -1; msg->qos_reset1 = -1; msg->qos_reset2 = -1; - msg->num_cll = 0; - msg->num_rngs = 0; + msg->saved_send_loop = s->in_send_loop[output_port]; int num_qos_levels = s->params->num_qos_levels; int output_chan = get_next_router_vcg(s, bf, msg, lp); //includes default output_chan setting functionality if qos not enabled @@ -4028,6 +5070,8 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes cur_entry = s->pending_msgs[output_port][output_chan]; + msg->dfdally_src_terminal_id = cur_entry->msg.dfdally_src_terminal_id; + assert(cur_entry != NULL); if(s->last_buf_full[output_port]) //5-12-19, same here as above comment @@ -4067,23 +5111,36 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes if(cur_entry->msg.packet_size < s->params->chunk_size) num_chunks++; - double bytetime = delay; - + /* Injection delay: Time taken for the data to be placed on the link/channel + * - Based on bandwidth + * Propagtion delay: Time taken for the data to cross the link and arrive at the reciever + * - A physical property of the material of teh link (eg. copper, optical fiber) + */ + tw_stime injection_ts, injection_delay; + tw_stime propagation_ts, propagation_delay; + + propagation_delay = delay; + injection_delay = bytes_to_ns(s->params->chunk_size, bandwidth); + if(cur_entry->msg.packet_size == 0) - bytetime = bytes_to_ns(s->params->credit_size, bandwidth); + injection_delay = bytes_to_ns(s->params->credit_size, bandwidth); if((cur_entry->msg.packet_size < s->params->chunk_size) && (cur_entry->msg.chunk_id == num_chunks - 1)) - bytetime = bytes_to_ns(cur_entry->msg.packet_size % s->params->chunk_size, bandwidth); + injection_delay = bytes_to_ns(cur_entry->msg.packet_size % s->params->chunk_size, bandwidth); - msg->num_rngs++; - ts = g_tw_lookahead + tw_rand_unif( lp->rng) + bytetime + s->params->router_delay; + injection_delay += s->params->router_delay; msg->saved_available_time = s->next_output_available_time[output_port]; s->next_output_available_time[output_port] = maxd(s->next_output_available_time[output_port], tw_now(lp)); - s->next_output_available_time[output_port] += ts; + s->next_output_available_time[output_port] += injection_delay; + + injection_ts = s->next_output_available_time[output_port] - tw_now(lp); + propagation_ts = injection_ts + propagation_delay; + + cur_entry->msg.this_router_ptp_latency = s->next_output_available_time[output_port] - cur_entry->msg.this_router_arrival; + msg->this_router_ptp_latency = cur_entry->msg.this_router_ptp_latency; - ts = s->next_output_available_time[output_port] - tw_now(lp); // dest can be a router or a terminal, so we must check void * m_data; if (to_terminal) { @@ -4092,13 +5149,11 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes printf("\n intra-group radix %d output port %d next stop %d", s->params->intra_grp_radix, output_port, cur_entry->msg.next_stop); assert(cur_entry->msg.next_stop == cur_entry->msg.dest_terminal_lpid); e = model_net_method_event_new(cur_entry->msg.next_stop, - s->next_output_available_time[output_port] - tw_now(lp), lp, - DRAGONFLY_DALLY, (void**)&m, &m_data); + propagation_ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY, (void**)&m, &m_data); } else { e = model_net_method_event_new(cur_entry->msg.next_stop, - s->next_output_available_time[output_port] - tw_now(lp), lp, - DRAGONFLY_DALLY_ROUTER, (void**)&m, &m_data); + propagation_ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&m, &m_data); } memcpy(m, &cur_entry->msg, sizeof(terminal_dally_message)); if (m->remote_event_size_bytes) { @@ -4130,8 +5185,13 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes s->link_traffic_ross_sample[output_port] += s->params->chunk_size; } + s->total_chunks[output_port]++; + if(cur_entry->msg.packet_ID == LLU(TRACK_PKT) && cur_entry->msg.src_terminal_id == T_ID) printf("\n Queuing at the router %d ", s->router_id); + + m->rail_id = msg->rail_id; + /* Determine the event type. If the packet has arrived at the final * destination router then it should arrive at the destination terminal * next.*/ @@ -4144,14 +5204,21 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes m->type = R_ARRIVE; } tw_event_send(e); - + + msg->saved_app_id = cur_entry->msg.app_id; + if (g_congestion_control_enabled) { + congestion_control_message *cc_msg_rc = cc_msg_rc_storage_create(); + cc_router_forwarded_packet(s->local_congestion_controller, lp, s->params->chunk_size, output_port, output_chan, cur_entry->msg.dfdally_src_terminal_id, cur_entry->msg.app_id, cc_msg_rc); + rc_stack_push(lp, cc_msg_rc, cc_msg_rc_storage_delete, s->cc_st); + } + cur_entry = return_head(s->pending_msgs[output_port], s->pending_msgs_tail[output_port], output_chan); rc_stack_push(lp, cur_entry, delete_terminal_dally_message_list, s->st); s->qos_data[output_port][vcg] += msg_size; s->next_output_available_time[output_port] -= s->params->router_delay; - ts -= s->params->router_delay; + injection_ts -= s->params->router_delay; int next_output_chan = get_next_router_vcg(s, bf, msg, lp); @@ -4165,11 +5232,10 @@ static void router_packet_send( router_state * s, tw_bf * bf, terminal_dally_mes assert(cur_entry != NULL); terminal_dally_message *m_new; - msg->num_rngs++; - ts += g_tw_lookahead + tw_rand_unif(lp->rng); - e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_DALLY_ROUTER, + e = model_net_method_event_new(lp->gid, injection_ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&m_new, NULL); m_new->type = R_SEND; + m_new->rail_id = msg->rail_id; m_new->magic = router_magic_num; m_new->vc_index = output_port; tw_event_send(e); @@ -4185,12 +5251,6 @@ static void router_buf_update_rc(router_state * s, int output_chan = msg->output_chan; s->vc_occupancy[indx][output_chan] += s->params->chunk_size; - for(int i = 0; i < msg->num_rngs; i++) - tw_rand_reverse_unif(lp->rng); - - for(int i = 0; i < msg->num_cll; i++) - codes_local_latency_reverse(lp); - if(bf->c3) { s->busy_time[indx] = msg->saved_rcv_time; @@ -4214,8 +5274,6 @@ static void router_buf_update_rc(router_state * s, /* Update the buffer space associated with this router LP */ static void router_buf_update(router_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { - msg->num_cll = 0; - msg->num_rngs = 0; int indx = msg->vc_index; int output_chan = msg->output_chan; @@ -4258,11 +5316,11 @@ static void router_buf_update(router_state * s, tw_bf * bf, terminal_dally_messa if(s->in_send_loop[indx] == 0 && s->pending_msgs[indx][output_chan] != NULL) { bf->c2 = 1; terminal_dally_message *m; - msg->num_cll++; - tw_stime ts = codes_local_latency(lp); - tw_event *e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_DALLY_ROUTER, + tw_stime ts = maxd(s->next_output_available_time[indx], tw_now(lp)) - tw_now(lp); + tw_event *e = model_net_method_event_new(lp->gid, ts + gen_noise(lp, &msg->num_rngs), lp, DRAGONFLY_DALLY_ROUTER, (void**)&m, NULL); m->type = R_SEND; + m->rail_id = msg->rail_id; m->vc_index = indx; m->magic = router_magic_num; s->in_send_loop[indx] = 1; @@ -4277,6 +5335,9 @@ terminal_dally_event( terminal_state * s, terminal_dally_message * msg, tw_lp * lp ) { + msg->num_cll = 0; + msg->num_rngs = 0; + s->fwd_events++; s->ross_sample.fwd_events++; //*(int *)bf = (int)0; @@ -4304,7 +5365,6 @@ terminal_dally_event( terminal_state * s, case T_BANDWIDTH: issue_bw_monitor_event(s, bf, msg, lp); break; - default: printf("\n LP %d Terminal message type not supported %d ", (int)lp->gid, msg->type); tw_error(TW_LOC, "Msg type not supported"); @@ -4314,9 +5374,14 @@ terminal_dally_event( terminal_state * s, void router_dally_event(router_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { + msg->num_cll = 0; + msg->num_rngs = 0; + s->fwd_events++; s->ross_rsample.fwd_events++; rc_stack_gc(lp, s->st); + + s->last_time = tw_now(lp); assert(msg->magic == router_magic_num); switch(msg->type) @@ -4340,6 +5405,10 @@ void router_dally_event(router_state * s, tw_bf * bf, terminal_dally_message * m // printf("%d: router bandwidth monitor event\n", s->router_id); issue_rtr_bw_monitor_event(s, bf, msg, lp); break; + + case R_SNAPSHOT: + router_handle_snapshot_event(s, bf, msg, lp); + break; default: printf("\n (%lf) [Router %d] Router Message type not supported %d dest " @@ -4353,6 +5422,12 @@ void router_dally_event(router_state * s, tw_bf * bf, terminal_dally_message * m /* Reverse computation handler for a terminal event */ void terminal_dally_rc_event_handler(terminal_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { + for(int i = 0; i < msg->num_rngs; i++) + tw_rand_reverse_unif(lp->rng); + + for(int i = 0; i < msg->num_cll; i++) + codes_local_latency_reverse(lp); + s->rev_events++; s->ross_sample.rev_events++; switch(msg->type) @@ -4380,12 +5455,20 @@ void terminal_dally_rc_event_handler(terminal_state * s, tw_bf * bf, terminal_da default: tw_error(TW_LOC, "\n Invalid terminal event type %d ", msg->type); } + msg->num_cll = 0; + msg->num_rngs = 0; } /* Reverse computation handler for a router event */ void router_dally_rc_event_handler(router_state * s, tw_bf * bf, terminal_dally_message * msg, tw_lp * lp) { + for(int i = 0; i < msg->num_rngs; i++) + tw_rand_reverse_unif(lp->rng); + + for(int i = 0; i < msg->num_cll; i++) + codes_local_latency_reverse(lp); + s->rev_events++; s->ross_rsample.rev_events++; @@ -4405,6 +5488,8 @@ void router_dally_rc_event_handler(router_state * s, tw_bf * bf, issue_rtr_bw_monitor_event_rc(s, bf, msg, lp); break; } + msg->num_cll = 0; + msg->num_rngs = 0; } /* dragonfly compute node and router LP types */ @@ -4466,10 +5551,10 @@ static void dfdally_select_intermediate_group(router_state *s, tw_bf *bf, termin msg->num_rngs++; int rand_group_id; if (NONMIN_INCLUDE_SOURCE_DEST) //then any group is a valid intermediate group - rand_group_id = tw_rand_integer(lp->rng, 0, s->params->num_groups-1); + rand_group_id = tw_rand_integer(lp->rng, s->params->num_groups*s->plane_id, (s->params->num_groups*(s->plane_id+1))-1); else { //then we don't consider source or dest groups as valid intermediate groups vector group_list; - for (int i = 0; i < s->params->num_groups; i++) + for (int i = s->params->num_groups*s->plane_id; i < s->params->num_groups*(s->plane_id+1); i++) { if ((i != origin_group_id) && (i != fdest_group_id)) { group_list.push_back(i); @@ -4485,7 +5570,7 @@ static void dfdally_select_intermediate_group(router_state *s, tw_bf *bf, termin assert(s->router_id != msg->origin_router_id); set< int > valid_intm_groups; - vector< Connection > global_conns = s->connMan->get_connections_by_type(CONN_GLOBAL); + vector< Connection > global_conns = s->connMan.get_connections_by_type(CONN_GLOBAL); for (vector::iterator it = global_conns.begin(); it != global_conns.end(); it ++) { Connection conn = *it; if (NONMIN_INCLUDE_SOURCE_DEST) //then any group I connect to is valid @@ -4516,30 +5601,48 @@ static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, int fdest_group_id = fdest_router_id / s->params->num_routers; if (my_group_id != fdest_group_id) { //we're in origin group or intermediate group - either way we need to route to fdest group minimally - vector< Connection > conns_to_dest_group = s->connMan->get_connections_to_group(fdest_group_id); + vector< Connection > conns_to_dest_group = s->connMan.get_connections_to_group(fdest_group_id); if (conns_to_dest_group.size() > 0) { //then we have a direct connection to dest group return conns_to_dest_group; // --------- return direct connection } + // else { //we don't have a direct connection to group and need list of routers in our group that do + // return s->connMan.get_routed_connections_to_group(fdest_group_id, true); //get list of connections that I have that go to a router in my group that go to dest group + // // --------- return non-direct connection (still minimal though) + // } else { //we don't have a direct connection to group and need list of routers in our group that do - vector< Connection > poss_next_conns_to_group; - set< int > poss_router_id_set_to_group; //TODO this might be a source of non-determinism(?) - for(int i = 0; i < connectionList[my_group_id][fdest_group_id].size(); i++) - { - int poss_router_id = connectionList[my_group_id][fdest_group_id][i]; - if (poss_router_id_set_to_group.count(poss_router_id) == 0) { //we only want to consider a single router id once (we look at all connections to it using the conn man) - vector< Connection > conns = s->connMan->get_connections_to_gid(poss_router_id, CONN_LOCAL); - poss_router_id_set_to_group.insert(poss_router_id); - poss_next_conns_to_group.insert(poss_next_conns_to_group.end(), conns.begin(), conns.end()); - } - } - return poss_next_conns_to_group; // --------- return non-direct connection (still minimal though) + vector poss_next_conns_to_group = s->connMan.get_routed_connections_to_group(fdest_group_id, true); + + // vector< Connection > poss_next_conns_to_group; + // set< int > poss_router_id_set_to_group; //TODO this might be a source of non-determinism(?) + // for(int i = 0; i < connectionList[my_group_id][fdest_group_id].size(); i++) + // { + // int poss_router_id = connectionList[my_group_id][fdest_group_id][i]; + // if (poss_router_id_set_to_group.count(poss_router_id) == 0) { //we only want to consider a single router id once (we look at all connections to it using the conn man) + // vector< Connection > conns = s->connMan.get_connections_to_gid(poss_router_id, CONN_LOCAL); + // poss_router_id_set_to_group.insert(poss_router_id); + // poss_next_conns_to_group.insert(poss_next_conns_to_group.end(), conns.begin(), conns.end()); + // } + // } + return poss_next_conns_to_group; } } else { //then we're in the final destination group, also we assume that we're not the fdest router assert(my_group_id == fdest_group_id); assert(my_router_id != fdest_router_id); //this should be handled outside of this function - vector< Connection > conns_to_fdest_router = s->connMan->get_connections_to_gid(fdest_router_id, CONN_LOCAL); + // if(netMan.is_link_failures_enabled()) { + // vector conns = s->connMan.get_connections_by_type(CONN_LOCAL); + // vector good_conns; + // for(int i = 0; i < conns.size(); i++) + // { + // int next_src_gid = conns[i].dest_gid; + // if(netMan.get_connection_manager_for_router(next_src_gid).is_any_connection_to(fdest_router_id)) + // good_conns.push_back(conns[i]); + // } + // return good_conns; + // } + + vector< Connection > conns_to_fdest_router = s->connMan.get_connections_to_gid(fdest_router_id, CONN_LOCAL); return conns_to_fdest_router; } } @@ -4556,8 +5659,7 @@ static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *b int preset_intm_group_id = msg->intm_grp_id; if (my_group_id == origin_group_id) { - vector< Connection > conns_to_intm_group = s->connMan->get_connections_to_group(preset_intm_group_id); - + vector< Connection > conns_to_intm_group = s->connMan.get_connections_to_group(preset_intm_group_id); //are we the originating router if (my_router_id == msg->origin_router_id) { //then we are able to route within our own group if necessary // Do we have direct connection to intermediate group? @@ -4565,14 +5667,15 @@ static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *b return conns_to_intm_group; } else { //no - route within group to router that DOES have a connection to intm group - vector connecting_router_ids = connectionList[my_group_id][preset_intm_group_id]; - vector< Connection > conns_to_connecting_routers; - for (int i = 0; i < connecting_router_ids.size(); i++) - { - int poss_router_id = connecting_router_ids[i]; - vector< Connection > candidate_conns = s->connMan->get_connections_to_gid(poss_router_id, CONN_LOCAL); - conns_to_connecting_routers.insert(conns_to_connecting_routers.end(), candidate_conns.begin(), candidate_conns.end()); - } + vector conns_to_connecting_routers = s->connMan.get_routed_connections_to_group(preset_intm_group_id, true); + // vector connecting_router_ids = connectionList[my_group_id][preset_intm_group_id]; + // vector< Connection > conns_to_connecting_routers; + // for (int i = 0; i < connecting_router_ids.size(); i++) + // { + // int poss_router_id = connecting_router_ids[i]; + // vector< Connection > candidate_conns = s->connMan.get_connections_to_gid(poss_router_id, CONN_LOCAL); + // conns_to_connecting_routers.insert(conns_to_connecting_routers.end(), candidate_conns.begin(), candidate_conns.end()); + // } return conns_to_connecting_routers; } } @@ -4582,7 +5685,7 @@ static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *b } else { //pick a new one! dfdally_select_intermediate_group(s, bf, msg, lp, fdest_router_id); - conns_to_intm_group = s->connMan->get_connections_to_group(msg->intm_grp_id); //new intm group id + conns_to_intm_group = s->connMan.get_connections_to_group(msg->intm_grp_id); //new intm group id return conns_to_intm_group; } } @@ -4606,23 +5709,24 @@ static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *b } } +//TODO - make some way to configure whether there's any form of adaptiveness to this scheme static Connection dfdally_minimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id) { vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "MINIMAL DEAD END\n"); + tw_error(TW_LOC, "%d group %d: MINIMAL DEAD END to %d in group %d - (s%d -> d%d)\n", s->router_id, s->group_id, fdest_router_id, fdest_router_id / s->params->num_routers, msg->origin_router_id, fdest_router_id); - ConnectionType conn_type = poss_next_stops[0].conn_type; //TODO this assumes that all possible next stops are of same type - OK for now, but remember this - if (conn_type == CONN_GLOBAL) { //TOOD should we really only randomize global and not local? should we really do light adaptive for nonglobal? + // ConnectionType conn_type = poss_next_stops[0].conn_type; //TODO this assumes that all possible next stops are of same type - OK for now, but remember this + // if (conn_type == CONN_GLOBAL) { //TOOD should we really only randomize global and not local? should we really do light adaptive for nonglobal? msg->num_rngs++; int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() - 1); return poss_next_stops[rand_sel]; - } - else - { - Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); - return best_min_conn; - } + // } + // else + // { + // Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + // return best_min_conn; + // } } // Coloquially: "Valiant Group Routing" @@ -4653,7 +5757,7 @@ static Connection dfdally_nonminimal_routing(router_state *s, tw_bf *bf, termina next_dest_group_id = msg->intm_grp_id; // Do I have a direct connection to the next_dest group? - vector< Connection > conns_to_next_group = s->connMan->get_connections_to_group(next_dest_group_id); + vector< Connection > conns_to_next_group = s->connMan.get_connections_to_group(next_dest_group_id); if (conns_to_next_group.size() > 0) { //Then yes I do msg->num_rngs++; int rand_sel = tw_rand_integer(lp->rng, 0, conns_to_next_group.size()-1); @@ -4661,18 +5765,24 @@ static Connection dfdally_nonminimal_routing(router_state *s, tw_bf *bf, termina return next_conn; } else { // I need to route to a router in my group that does have a direct connection to the intermediate group - vector connecting_router_ids = connectionList[my_group_id][next_dest_group_id]; - assert(connecting_router_ids.size() > 0); - msg->num_rngs++; - int rand_sel = tw_rand_integer(lp->rng, 0, connecting_router_ids.size()-1); - int conn_router_id = connecting_router_ids[rand_sel]; - - //There may be parallel connections to the same router - randomly select from them - vector< Connection > conns_to_next_router = s->connMan->get_connections_to_gid(conn_router_id, CONN_LOCAL); - assert(conns_to_next_router.size() > 0); + vector connections_toward_next_group = s->connMan.get_routed_connections_to_group(next_dest_group_id, true); + // vector connecting_router_ids = connectionList[my_group_id][next_dest_group_id]; + // assert(connecting_router_ids.size() > 0); + // msg->num_rngs++; + // int rand_sel = tw_rand_integer(lp->rng, 0, connecting_router_ids.size()-1); + // int conn_router_id = connecting_router_ids[rand_sel]; + + // //There may be parallel connections to the same router - randomly select from them + // vector< Connection > conns_to_next_router = s->connMan.get_connections_to_gid(conn_router_id, CONN_LOCAL); + // assert(conns_to_next_router.size() > 0); + // msg->num_rngs++; + // rand_sel = tw_rand_integer(lp->rng, 0, conns_to_next_router.size()-1); + // Connection next_conn = conns_to_next_router[rand_sel]; + + int rand_sel = tw_rand_integer(lp->rng, 0, connections_toward_next_group.size()-1); msg->num_rngs++; - rand_sel = tw_rand_integer(lp->rng, 0, conns_to_next_router.size()-1); - Connection next_conn = conns_to_next_router[rand_sel]; + Connection next_conn = connections_toward_next_group[rand_sel]; + return next_conn; } } @@ -4736,6 +5846,225 @@ static Connection dfdally_prog_adaptive_routing(router_state *s, tw_bf *bf, term } } +//SMART ROUTING: Smart routing is my term for failure aware routing. Leverages the network manager's ability to filter out invalid connections and to return only valid paths between endpoints. +//It's significantly slower in runtime, typically, and is very experimental at this point. Use at own risk. + +//when using this function, you should assume that the self router is NOT the destination. That should be handled elsewhere. +static set< Connection> get_smart_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id, int max_global_hops_in_path) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + int fdest_group_id = fdest_router_id / s->params->num_routers; + + set possible_next_dests; + + if (my_group_id == fdest_group_id) { //we're in origin group or intermediate group - either way we need to route to fdest group minimally + vector< Connection > conns_to_fdest_router = s->connMan.get_connections_to_gid(fdest_router_id, CONN_LOCAL); + if(conns_to_fdest_router.size() > 0) { + possible_next_dests.insert(conns_to_fdest_router.begin(),conns_to_fdest_router.end()); + return possible_next_dests; + } + } + // vector shortest_path_next_gids = netMan.get_shortest_nexts(s->router_id, fdest_router_id); + // for(vector::iterator it = shortest_path_next_gids.begin(); it != shortest_path_next_gids.end(); it++) + // { + // vector local_conns; + // vector global_conns; + // if(msg->my_hops_cur_group < max_hops_per_group) + // local_conns = s->connMan.get_connections_to_gid(*it,CONN_LOCAL); + // if(msg->my_g_hop < max_global_hops_in_path) + // global_conns = s->connMan.get_connections_to_gid(*it,CONN_GLOBAL); + + // vector::iterator it2; + // for(it2 = local_conns.begin(); it2 != local_conns.end(); it2++) + // { + // if (netMan.get_valid_next_hops_conns(it2->dest_gid,fdest_router_id,(max_hops_per_group-(msg->my_hops_cur_group+1)), (max_global_hops_in_path-msg->my_g_hop)).size()) + // possible_next_dests.insert(*it2); + // } + // for(it2 = global_conns.begin(); it2 != global_conns.end(); it2++) + // { + // if (netMan.get_valid_next_hops_conns(it2->dest_gid,fdest_router_id,(max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_in_path-(msg->my_g_hop+1))).size()) + // possible_next_dests.insert(*it2); + // } + // } + // if (possible_next_dests.size() < 1) + // { + if(s->group_id == fdest_router_id / s->params->num_routers) + { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), 0); + } + else { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_in_path-msg->my_g_hop)); + } + + // return possible_next_dests; + // } + return possible_next_dests; +} + +//when using this function, you should assume that the self router is NOT the destination. That should be handled elsewhere. +static set< Connection> get_smart_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id) +{ + return get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id, max_global_hops_minimal); +} + +static set get_smart_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id) +{ + set possible_next_dests; + if(s->group_id == fdest_router_id / s->params->num_routers) + { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), 0); + if (possible_next_dests.size() == 0) + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_nonminimal-msg->my_g_hop)); + } + else { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_nonminimal-msg->my_g_hop)); + } + + return possible_next_dests; +} + +static Connection dfdally_smart_minimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + if(s->router_id == fdest_router_id) + { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No connection to destination terminal %d\n", s->router_id, msg->dfdally_dest_terminal_id); //shouldn't happen unless math was wrong + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_conn; + } + //do i have a direct connection to fdest by any chance? + vector direct_conns; + if(my_group_id != fdest_group_id) + direct_conns = s->connMan.get_connections_to_gid(fdest_router_id,CONN_GLOBAL); + else + direct_conns = s->connMan.get_connections_to_gid(fdest_router_id,CONN_LOCAL); + if (direct_conns.size() > 0) { + msg->num_rngs++; + int offset = tw_rand_integer(lp->rng,0,direct_conns.size()-1); + return direct_conns[offset]; + } + else + { + set possible_conns = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + + if (possible_conns.size() < 1) + tw_error(TW_LOC, "Smart Routing: Pathfinder messed up\n"); + + + msg->num_rngs++; + int offset = tw_rand_integer(lp->rng,0,possible_conns.size()-1); + set::iterator it = possible_conns.begin(); + advance(it, offset); + return *(it); + } +} + +static Connection dfdally_smart_nonminimal_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + if(s->router_id == fdest_router_id) + { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No connection to destination terminal %d\n", s->router_id, msg->dfdally_dest_terminal_id); //shouldn't happen unless math was wrong + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_conn; + } + + if (my_group_id != origin_group_id && my_group_id != fdest_group_id) + msg->path_type = NON_MINIMAL; + + set possible_conns = get_smart_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + + if (possible_conns.size() < 1) + tw_error(TW_LOC, "Smart Routing: Pathfinder messed up\n"); + + msg->num_rngs++; + int offset = tw_rand_integer(lp->rng,0,possible_conns.size()-1); + set::iterator it = possible_conns.begin(); + advance(it, offset); + return *(it); +} + +static Connection dfdally_smart_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_dally_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + int adaptive_threshold = s->params->adaptive_threshold; + + if (my_router_id == fdest_router_id) // we're the destination, send to connected terminal + { + if(s->router_id == fdest_router_id) + { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No connection to destination terminal %d\n", s->router_id, msg->dfdally_dest_terminal_id); //shouldn't happen unless math was wrong + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_conn; + } + } + + if (my_group_id != origin_group_id && my_group_id != fdest_group_id) + msg->is_intm_visited = 1; + + if (msg->is_intm_visited == 1) //then we route minimally the rest of the way + { + set poss_min_next_stops = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id, max_global_hops_nonminimal); + return get_absolute_best_connection_from_conn_set(s, bf, msg, lp, poss_min_next_stops); + } + else + { + if(msg->path_type == NON_MINIMAL) + { + set poss_next_stops = get_smart_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Smart Prog Adaptive Routing: intm can't reach intm rtr"); + Connection best_conn = dfdally_get_best_from_k_connection_set(s,bf,msg,lp,poss_next_stops,s->params->global_k_picks); + return best_conn; + } + else { + if (my_group_id == origin_group_id) + { + set poss_min_next_stops = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + set poss_non_min_next_stops = get_smart_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + + Connection best_min_conn = dfdally_get_best_from_k_connection_set(s,bf,msg,lp,poss_min_next_stops,s->params->global_k_picks); + Connection best_nonmin_conn = dfdally_get_best_from_k_connection_set(s,bf,msg,lp,poss_non_min_next_stops,s->params->global_k_picks); + + int min_score = dfdally_score_connection(s, bf, msg, lp, best_min_conn, C_MIN); + int nonmin_score = dfdally_score_connection(s, bf, msg, lp, best_nonmin_conn, C_NONMIN); + + if (min_score <= adaptive_threshold) + return best_min_conn; + else if (min_score <= nonmin_score) + return best_min_conn; + else { + msg->path_type = NON_MINIMAL; + return best_nonmin_conn; + } + } else + { + set poss_min_next_stops = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id, max_global_hops_nonminimal); + return dfdally_get_best_from_k_connection_set(s, bf, msg, lp, poss_min_next_stops,s->params->global_k_picks); + } + } + } +} + /* LEGACY DRAGONFLY DALLY ROUTING - Sept. 2019, the state of dragonfly routing became difficult to maintain. There is little documentation to justify decisions in the code and consequently it is near impossible to tell @@ -4799,8 +6128,8 @@ static void do_local_adaptive_routing_legacy(router_state * s, int next_min_stop = dest_router_id; //was a vector of one in original - this is equivalent to what it did int next_nonmin_stop = intm_router_id; //was a vector of one - Connection min_conn = s->connMan->get_connections_to_gid(next_min_stop, CONN_LOCAL)[0]; - Connection nonmin_conn = s->connMan->get_connections_to_gid(next_nonmin_stop, CONN_LOCAL)[0]; + Connection min_conn = s->connMan.get_connections_to_gid(next_min_stop, CONN_LOCAL)[0]; + Connection nonmin_conn = s->connMan.get_connections_to_gid(next_nonmin_stop, CONN_LOCAL)[0]; int min_score = dfdally_score_connection(s, bf, msg, lp, min_conn, C_MIN); int nonmin_score = dfdally_score_connection(s, bf, msg, lp, nonmin_conn, C_NONMIN); @@ -4882,7 +6211,7 @@ static int get_output_port_legacy(router_state *s, terminal_dally_message *msg, if((tw_lpid)next_stop == msg->dest_terminal_lpid) { - Connection term_conn = s->connMan->get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL)[0]; + Connection term_conn = s->connMan.get_connections_to_gid(msg->dfdally_dest_terminal_id, CONN_TERMINAL)[0]; output_port = term_conn.port; } else @@ -4893,7 +6222,7 @@ static int get_output_port_legacy(router_state *s, terminal_dally_message *msg, if(intm_grp_id != s->group_id) { /* traversing a global channel */ - vector< Connection > conns_to_intm_grp = s->connMan->get_connections_to_group(intm_grp_id); + vector< Connection > conns_to_intm_grp = s->connMan.get_connections_to_group(intm_grp_id); if (conns_to_intm_grp.size() == 0) printf("\n Source router %d intm_grp_id %d ", src_router, intm_grp_id); @@ -4911,7 +6240,7 @@ static int get_output_port_legacy(router_state *s, terminal_dally_message *msg, } else { - vector< Connection > conns_to_local_router = s->connMan->get_connections_to_gid(local_router_id, CONN_LOCAL); + vector< Connection > conns_to_local_router = s->connMan.get_connections_to_gid(local_router_id, CONN_LOCAL); (*rng_counter)++; rand_offset = tw_rand_integer(lp->rng, 0, conns_to_local_router.size()-1); @@ -4974,7 +6303,7 @@ static tw_lpid get_next_stop_legacy(router_state *s, tw_lp *lp, tw_bf *bf, termi * (global ports) */ if(get_direct_con) { - if(s->connMan->get_connections_to_group(dest_group_id).size() > 1) //NTODO - this looks like maybe it should be >= 1 + if(s->connMan.get_connections_to_group(dest_group_id).size() > 1) //NTODO - this looks like maybe it should be >= 1 select_chan = find_chan_legacy(s->router_id, dest_group_id, s->params->num_routers); else { @@ -4995,7 +6324,7 @@ static tw_lpid get_next_stop_legacy(router_state *s, tw_lp *lp, tw_bf *bf, termi if(s->router_id == msg->saved_src_dest) { - vector< Connection > conns_to_dest_group = s->connMan->get_connections_to_group(dest_group_id); + vector< Connection > conns_to_dest_group = s->connMan.get_connections_to_group(dest_group_id); (*rng_counter)++; select_chan = tw_rand_integer(lp->rng, 0, conns_to_dest_group.size() - 1); dest_lp = conns_to_dest_group[select_chan].dest_gid; @@ -5074,7 +6403,7 @@ static int do_global_adaptive_routing_legacy(router_state *s, tw_lp *lp, termina noIntraA = false; if(min_rtr_a == s->router_id) { noIntraA = true; - min_rtr_a = s->connMan->get_connections_to_group(dest_grp_id)[0].dest_gid; + min_rtr_a = s->connMan.get_connections_to_group(dest_grp_id)[0].dest_gid; } if(num_min_chans > 1) { assert(min_chan_b >= 0); @@ -5083,7 +6412,7 @@ static int do_global_adaptive_routing_legacy(router_state *s, tw_lp *lp, termina if(min_rtr_b == s->router_id) { noIntraB = true; - min_rtr_b = s->connMan->get_connections_to_group(dest_grp_id)[0].dest_gid; + min_rtr_b = s->connMan.get_connections_to_group(dest_grp_id)[0].dest_gid; } } @@ -5138,7 +6467,7 @@ static int do_global_adaptive_routing_legacy(router_state *s, tw_lp *lp, termina if(nonmin_chan_a != -1) { /* TODO: For a 2-D dragonfly, this can be more than one link. */ noIntraA = true; - nonmin_rtr_a = s->connMan->get_connections_to_group(intm_grp_id_a)[0].dest_gid; + nonmin_rtr_a = s->connMan.get_connections_to_group(intm_grp_id_a)[0].dest_gid; } else { @@ -5148,7 +6477,7 @@ static int do_global_adaptive_routing_legacy(router_state *s, tw_lp *lp, termina if(nonmin_rtr_a == s->router_id) { noIntraA = true; - nonmin_rtr_a = s->connMan->get_connections_to_group(intm_grp_id_a)[0].dest_gid; //NOTE: This line did not exist in the original but I believe this was what was supposed to happen and it won't work without it, otherwise nonmin_rtr_* is THIS ROUTER + nonmin_rtr_a = s->connMan.get_connections_to_group(intm_grp_id_a)[0].dest_gid; //NOTE: This line did not exist in the original but I believe this was what was supposed to happen and it won't work without it, otherwise nonmin_rtr_* is THIS ROUTER } } @@ -5159,7 +6488,7 @@ static int do_global_adaptive_routing_legacy(router_state *s, tw_lp *lp, termina if(nonmin_chan_b != -1) { bf->c26=1; noIntraB = true; - nonmin_rtr_b = s->connMan->get_connections_to_group(intm_grp_id_b)[0].dest_gid; + nonmin_rtr_b = s->connMan.get_connections_to_group(intm_grp_id_b)[0].dest_gid; } else { @@ -5169,7 +6498,7 @@ static int do_global_adaptive_routing_legacy(router_state *s, tw_lp *lp, termina if(nonmin_rtr_b == s->router_id) { noIntraB = true; - nonmin_rtr_b = s->connMan->get_connections_to_group(intm_grp_id_b)[0].dest_gid; //NOTE: This line did not exist in the original but I believe this was what was supposed to happen and it won't work without it, otherwise nonmin_rtr_* is THIS ROUTER + nonmin_rtr_b = s->connMan.get_connections_to_group(intm_grp_id_b)[0].dest_gid; //NOTE: This line did not exist in the original but I believe this was what was supposed to happen and it won't work without it, otherwise nonmin_rtr_* is THIS ROUTER } } assert(nonmin_chan_b >= 0); @@ -5295,14 +6624,14 @@ static Connection dfdally_prog_adaptive_legacy_routing(router_state *s, tw_bf *b vector direct_rtrs; int dest_idx = tw_rand_integer(lp->rng, 0, num_routers - 1); //local intra id of routers msg->num_rngs++; - vector groups_i_connect_to = s->connMan->get_connected_group_ids(); + vector groups_i_connect_to = s->connMan.get_connected_group_ids(); vector::iterator it = groups_i_connect_to.begin(); for (; it != groups_i_connect_to.end(); it++) { int begin = *it * num_routers; //first router index of this group int gid = begin + dest_idx; - int num_conns_to_group = s->connMan->get_connections_to_group(*it).size(); + int num_conns_to_group = s->connMan.get_connections_to_group(*it).size(); for (int i = 0; i < num_conns_to_group; i++) //old version adds same router the order of the number of connections to said group //NTODO this is probably an error in the original { direct_rtrs.push_back(gid); @@ -5422,7 +6751,7 @@ static Connection dfdally_prog_adaptive_legacy_routing(router_state *s, tw_bf *b output_port = get_output_port_legacy(s, msg, lp, bf, next_stop, &(msg->num_rngs)); assert(output_port >= 0); - Connection return_conn = s->connMan->get_connection_on_port(output_port); + Connection return_conn = s->connMan.get_connection_on_port(output_port); return return_conn; } @@ -5449,6 +6778,11 @@ struct model_net_method dragonfly_dally_method = NULL,//(final_f)dragonfly_dally_sample_fin custom_dally_dragonfly_register_model_types, custom_dally_dragonfly_get_model_types, + (event_f)dragonfly_dally_terminal_end_sim_notif, + (revent_f)dragonfly_dally_terminal_end_sim_notif_rc, + (event_f)dragonfly_dally_terminal_congestion_event, + (revent_f)dragonfly_dally_terminal_congestion_event_rc, + (commit_f)dragonfly_dally_terminal_congestion_event_commit, }; struct model_net_method dragonfly_dally_router_method = @@ -5471,6 +6805,11 @@ struct model_net_method dragonfly_dally_router_method = NULL,//(final_f)dragonfly_dally_rsample_fin custom_dally_router_register_model_types, custom_dally_dfly_router_get_model_types, + (event_f)dragonfly_dally_router_end_sim_notif, + (revent_f)dragonfly_dally_router_end_sim_notif_rc, + (event_f)dragonfly_dally_router_congestion_event, + (revent_f)dragonfly_dally_router_congestion_event_rc, + (commit_f)dragonfly_dally_router_congestion_event_commit, }; // #ifdef ENABLE_CORTEX @@ -5775,3 +7114,13 @@ struct model_net_method dragonfly_dally_router_method = // #endif } + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/networks/model-net/dragonfly-plus.C b/src/networks/model-net/dragonfly-plus.C index 956fba00..7a80d65a 100644 --- a/src/networks/model-net/dragonfly-plus.C +++ b/src/networks/model-net/dragonfly-plus.C @@ -24,7 +24,7 @@ #include "codes/rc-stack.h" #include "sys/file.h" -#include "codes/connection-manager.h" +#include "codes/network-manager/dragonfly-network-manager.h" #ifdef ENABLE_CORTEX #include @@ -41,6 +41,13 @@ // maximum number of characters allowed to represent the routing algorithm as a string #define MAX_ROUTING_CHARS 32 +#define ROUTER_BW_LOG 0 + +//Routing Defines +//NONMIN_INCLUDE_SOURCE_DEST: Do we allow source and destination groups to be viable choces for indirect group (i.e. do we allow nonminimal routing to sometimes be minimal?) +#define NONMIN_INCLUDE_SOURCE_DEST 0 +//End routing defines + // debugging parameters #define TRACK -1 #define TRACK_PKT 0 @@ -56,9 +63,10 @@ using namespace std; /*MM: Maintains a list of routers connecting the source and destination groups */ -static vector< vector< vector< int > > > connectionList; +// static vector< vector< vector< int > > > connectionList; -static vector< ConnectionManager > connManagerList; +static DragonflyNetworkManager netMan; +// static vector< DragonflyConnectionManager > connManagerList; /* IntraGroupLink is a struct used to unpack binary data regarding inter group connections from the supplied inter-group file. This struct should not be @@ -125,10 +133,15 @@ static long num_local_packets_sr = 0; static long num_local_packets_sg = 0; static long num_remote_packets = 0; +static int max_hops_per_group = 2; +static int max_global_hops_nonminimal = 2; +static int max_global_hops_minimal = 1; + /* Hops within a group */ static int num_intra_nonmin_hops = 4; static int num_intra_min_hops = 2; + static FILE *dragonfly_log = NULL; static int sample_bytes_written = 0; @@ -226,6 +239,9 @@ struct dragonfly_plus_param { // configuration parameters int num_routers; /*Number of routers in a group*/ + int num_injection_queues; + int num_rails; + int num_planes; double local_bandwidth; /* bandwidth of the router-router channels within a group */ double global_bandwidth; /* bandwidth of the inter-group router connections */ double cn_bandwidth; /* bandwidth of the compute node channels connected to routers */ @@ -234,8 +250,10 @@ struct dragonfly_plus_param int global_vc_size; /* buffer size of the global channels */ int cn_vc_size; /* buffer size of the compute node channels */ int chunk_size; /* full-sized packets are broken into smaller chunks.*/ + int global_k_picks; // derived parameters int num_cn; + int cn_radix; int intra_grp_radix; // qos params @@ -247,6 +265,10 @@ struct dragonfly_plus_param int num_router_leaf; // number of leaf routers (bottom level) int adaptive_threshold; // predefined queue length threshold T before a packet is routed through a lower priority queue + int rail_select; + int num_rails_per_plane; + int num_routers_per_plane; + bool source_leaf_consider_nonmin; bool int_spine_consider_min; bool dest_spine_consider_nonmin; @@ -258,6 +280,7 @@ struct dragonfly_plus_param // dfp params end int num_groups; + int total_groups; int radix; int total_routers; int total_terminals; @@ -304,7 +327,7 @@ struct dfly_cn_sample long data_size_sample; double fin_hops_sample; tw_stime fin_chunks_time; - tw_stime busy_time_sample; + tw_stime* busy_time_sample; tw_stime end_time; long fwd_events; long rev_events; @@ -354,8 +377,8 @@ typedef enum qos_status Q_OVERBW, } qos_status; -// Used to denote whether a connection is one that would allow a packet to continue along a minimal path or not -// Specifically used to clearly pass whether a connection is a minimal one through to the connection scoring function +// Used to denote whether a Connection is one that would allow a packet to continue along a minimal path or not +// Specifically used to clearly pass whether a Connection is a minimal one through to the Connection scoring function typedef enum conn_minimality_t { C_MIN = 1, @@ -369,9 +392,21 @@ typedef enum routing_alg_t NON_MINIMAL_LEAF, //will always route through an intermediate leaf in an intermediate group for inter group traffic PROG_ADAPTIVE, //Choose between Minimal, Nonmin spine, and nonmin leaf at the router level based on own congestion FULLY_PROG_ADAPTIVE, //OTFA with ARNs - NON_MINIMAL //A catch all for adaptive routing to determine if a path had deviated from minimal - not an algorithm!!!!! + NON_MINIMAL, //A catch all for adaptive routing to determine if a path had deviated from minimal - not an algorithm!!!!! + SMART_MINIMAL, + SMART_NON_MINIMAL, + SMART_PROG_ADAPTIVE } routing_alg_t; +typedef enum rail_selection_alg_t +{ + RAIL_CONGESTION=1, // Selects rail with minimal injection congestion + RAIL_PATH, // Selects the rail that provides minimal path congestion is tie breaker + RAIL_DEDICATED, // Selects a specific rail + RAIL_RAND +} rail_selection_alg_t; + + typedef enum route_scoring_metric_t { ALPHA = 1, //Count queue lengths and pending messages for a port @@ -420,6 +455,16 @@ static char* get_routing_alg_chararray(int routing_alg_int) break; case FULLY_PROG_ADAPTIVE: strcpy(rt_alg, "FULL_PROG_ADAPTIVE"); + break; + case SMART_PROG_ADAPTIVE: + strcpy(rt_alg, "SMART_PROG_ADAPTIVE"); + break; + case SMART_MINIMAL: + strcpy(rt_alg, "SMART_MINIMAL"); + break; + case SMART_NON_MINIMAL: + strcpy(rt_alg, "SMART_NON_MINIMAL"); + break; default: tw_error(TW_LOC, "Routing Algorithm is UNDEFINED - did you call get_routing_alg_string() before setting the static global variable: 'routing'?"); break; @@ -429,7 +474,7 @@ static char* get_routing_alg_chararray(int routing_alg_int) static bool isRoutingAdaptive(int alg) { - if (alg == PROG_ADAPTIVE || alg == FULLY_PROG_ADAPTIVE) + if (alg == PROG_ADAPTIVE || alg == FULLY_PROG_ADAPTIVE || alg == SMART_PROG_ADAPTIVE) return true; else return false; @@ -437,7 +482,7 @@ static bool isRoutingAdaptive(int alg) static bool isRoutingMinimal(int alg) { - if (alg == MINIMAL) + if (alg == MINIMAL || alg == SMART_MINIMAL) return true; else return false; @@ -445,12 +490,21 @@ static bool isRoutingMinimal(int alg) static bool isRoutingNonminimalExplicit(int alg) { - if (alg == NON_MINIMAL_LEAF || alg == NON_MINIMAL_SPINE) + if (alg == NON_MINIMAL_LEAF || alg == NON_MINIMAL_SPINE || alg == SMART_NON_MINIMAL) return true; else return false; } +static bool isRoutingSmart(int alg) +{ + if (alg == SMART_MINIMAL || alg == SMART_PROG_ADAPTIVE || alg == SMART_NON_MINIMAL) + return true; + else + return false; +} + + /* handles terminal and router events like packet generate/send/receive/buffer */ typedef struct terminal_state terminal_state; typedef struct router_state router_state; @@ -466,27 +520,30 @@ struct terminal_state int total_gen_size; // Dragonfly specific parameters - unsigned int router_id; + tw_lpid* router_lp; //one per rail + unsigned int* router_id; //one per rail unsigned int terminal_id; + DragonflyConnectionManager connMan; + // Each terminal will have an input and output channel with the router - int *vc_occupancy; // NUM_VC + int** vc_occupancy; // [rail_id][qos_level] int num_vcs; - tw_stime terminal_available_time; - terminal_plus_message_list **terminal_msgs; - terminal_plus_message_list **terminal_msgs_tail; - int in_send_loop; + tw_stime* terminal_available_time; // [rail_id] + terminal_plus_message_list ***terminal_msgs; //[rail_id][qos_level] + terminal_plus_message_list ***terminal_msgs_tail; //[rail_id][qos_level] + int* in_send_loop; //[rail_id] struct mn_stats dragonfly_stats_array[CATEGORY_MAX]; - int * qos_status; - unsigned long long* qos_data; + int ** qos_status; //[rail_id][qos_level] + int** qos_data; //[rail_id][qos_level] - int last_qos_lvl; + int* last_qos_lvl; //[rail_id] int is_monitoring_bw; struct rc_stack *st; - int issueIdle; - unsigned long long * terminal_length; + int *issueIdle; //[rail_id] + int** terminal_length; //[rail_id][qos_level] const char *anno; const dragonfly_plus_param *params; @@ -501,10 +558,11 @@ struct terminal_state long finished_chunks; long finished_packets; - tw_stime last_buf_full; - tw_stime busy_time; + tw_stime* last_buf_full; //[rail_id] + tw_stime* busy_time; //[rail_id] + uint64_t* link_traffic; //[rail_id] - unsigned long stalled_chunks; //Counter for when a packet cannot be immediately routed due to full VC + unsigned long* stalled_chunks; //Counter for when a packet cannot be immediately routed due to full VC - [rail_id] tw_stime max_latency; tw_stime min_latency; @@ -519,7 +577,7 @@ struct terminal_state long data_size_sample; double fin_hops_sample; tw_stime fin_chunks_time; - tw_stime busy_time_sample; + tw_stime* busy_time_sample; char sample_buf[4096]; struct dfly_cn_sample *sample_stat; @@ -535,7 +593,7 @@ struct terminal_state long data_size_ross_sample; long fin_hops_ross_sample; tw_stime fin_chunks_time_ross_sample; - tw_stime busy_time_ross_sample; + tw_stime* busy_time_ross_sample; struct dfly_cn_sample ross_sample; }; @@ -543,12 +601,13 @@ struct router_state { int router_id; int group_id; + int plane_id; int op_arr_size; int max_arr_size; router_type dfp_router_type; // Enum to specify whether this router is a spine or a leaf - ConnectionManager *connMan; + DragonflyConnectionManager connMan; int *gc_usage; int *global_channel; @@ -679,10 +738,13 @@ void dfly_plus_model_stat_collect(terminal_state *s, tw_lp *lp, char *buffer) index += sizeof(tmp2); s->fin_chunks_time_ross_sample = 0; - tmp2 = s->busy_time_ross_sample; - memcpy(&buffer[index], &tmp2, sizeof(tmp2)); - index += sizeof(tmp2); - s->busy_time_ross_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + { + tmp2 = s->busy_time_ross_sample[i]; + memcpy(&buffer[index], &tmp2, sizeof(tmp2)); + index += sizeof(tmp2); + s->busy_time_ross_sample[i] = 0; + } return; } @@ -803,7 +865,9 @@ static void ross_dfly_plus_sample_fn(terminal_state * s, tw_bf * bf, tw_lp * lp, sample->data_size_sample = s->ross_sample.data_size_sample; sample->fin_hops_sample = s->ross_sample.fin_hops_sample; sample->fin_chunks_time = s->ross_sample.fin_chunks_time; - sample->busy_time_sample = s->ross_sample.busy_time_sample; + sample->busy_time_sample = (tw_stime*)((&sample->busy_time_sample[0] + s->params->num_rails)); + for(int i = 0; i < s->params->num_rails; i++) + sample->busy_time_sample[i] = s->ross_sample.busy_time_sample[i]; sample->end_time = tw_now(lp); sample->fwd_events = s->fwd_events; sample->rev_events = s->rev_events; @@ -814,7 +878,8 @@ static void ross_dfly_plus_sample_fn(terminal_state * s, tw_bf * bf, tw_lp * lp, s->fwd_events = 0; s->rev_events = 0; s->ross_sample.fin_chunks_time = 0; - s->ross_sample.busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + s->ross_sample.busy_time_sample[i] = 0; } // virtual time sampling callback - terminal reverse @@ -823,7 +888,8 @@ static void ross_dfly_plus_sample_rc_fn(terminal_state * s, tw_bf * bf, tw_lp * (void)lp; (void)bf; - s->ross_sample.busy_time_sample = sample->busy_time_sample; + for(int i = 0; i < s->params->num_rails; i++) + s->ross_sample.busy_time_sample[i] = sample->busy_time_sample[i]; s->ross_sample.fin_chunks_time = sample->fin_chunks_time; s->ross_sample.fin_hops_sample = sample->fin_hops_sample; s->ross_sample.data_size_sample = sample->data_size_sample; @@ -965,12 +1031,17 @@ void dragonfly_plus_sample_init(terminal_state *s, tw_lp *lp) s->data_size_sample = 0; s->fin_hops_sample = 0; s->fin_chunks_time = 0; - s->busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + s->busy_time_sample[i] = 0; s->op_arr_size = 0; s->max_arr_size = MAX_STATS; s->sample_stat = (dfly_cn_sample *) calloc(MAX_STATS, sizeof(struct dfly_cn_sample)); + for(int i = 0; i < s->max_arr_size; i++) + { + s->sample_stat[i].busy_time_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); + } } void dragonfly_plus_sample_rc_fn(terminal_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp) { @@ -981,7 +1052,8 @@ void dragonfly_plus_sample_rc_fn(terminal_state *s, tw_bf *bf, terminal_plus_mes s->op_arr_size--; int cur_indx = s->op_arr_size; struct dfly_cn_sample stat = s->sample_stat[cur_indx]; - s->busy_time_sample = stat.busy_time_sample; + for(int i = 0; i < s->params->num_rails; i++) + s->busy_time_sample[i] = stat.busy_time_sample[i]; s->fin_chunks_time = stat.fin_chunks_time; s->fin_hops_sample = stat.fin_hops_sample; s->data_size_sample = stat.data_size_sample; @@ -1024,7 +1096,8 @@ void dragonfly_plus_sample_fn(terminal_state *s, tw_bf *bf, terminal_plus_messag s->sample_stat[cur_indx].data_size_sample = s->data_size_sample; s->sample_stat[cur_indx].fin_hops_sample = s->fin_hops_sample; s->sample_stat[cur_indx].fin_chunks_time = s->fin_chunks_time; - s->sample_stat[cur_indx].busy_time_sample = s->busy_time_sample; + for(int i = 0; i < s->params->num_rails; i++) + s->sample_stat[cur_indx].busy_time_sample[i] = s->busy_time_sample[i]; s->sample_stat[cur_indx].end_time = tw_now(lp); s->sample_stat[cur_indx].fwd_events = s->fwd_events; s->sample_stat[cur_indx].rev_events = s->rev_events; @@ -1036,7 +1109,8 @@ void dragonfly_plus_sample_fn(terminal_state *s, tw_bf *bf, terminal_plus_messag s->fwd_events = 0; s->rev_events = 0; s->fin_chunks_time = 0; - s->busy_time_sample = 0; + for(int i = 0; i < s->params->num_rails; i++) + s->busy_time_sample[i] = 0; } void dragonfly_plus_sample_fin(terminal_state *s, tw_lp *lp) @@ -1072,21 +1146,30 @@ void dragonfly_plus_sample_fin(terminal_state *s, tw_lp *lp) sample_bytes_written += (s->op_arr_size * sizeof(struct dfly_cn_sample)); } -int dragonfly_plus_get_assigned_router_id(int terminal_id, const dragonfly_plus_param *p); +int dragonfly_plus_get_assigned_router_id(const dragonfly_plus_param *p, int terminal_id, int rail_id); static short routing = MINIMAL; static short scoring = ALPHA; static short scoring_preference = LOWER; /*Routing Implementation Declarations*/ -static Connection do_dfp_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); -static Connection do_dfp_FPAR(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_minimal_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_nonminimal_leaf_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_fully_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_smart_minimal_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_smart_nonminimal_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static Connection dfp_smart_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); /*Routing Helper Declarations*/ static int get_min_hops_to_dest_from_conn(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, Connection conn); static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); -static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, vector< Connection > possible_minimal_stops, int fdest_router_id); +static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static void dfp_select_intermediate_group(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id); +static set< Connection> get_smart_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id, int max_global_hops_in_path); + +map,bool> _accessibility_map; static tw_stime dragonfly_total_time = 0; @@ -1156,7 +1239,7 @@ static void free_tmp(void *ptr) } /** - * Scores a connection based on the metric provided in the function + * Scores a Connection based on the metric provided in the function * @param isMinimalPort a boolean variable used in the Gamma metric to pass whether a given port would lead to the destination in a minimal way */ static int dfp_score_connection(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, Connection conn, conn_minimality_t c_minimality) @@ -1185,7 +1268,7 @@ static int dfp_score_connection(router_state *s, tw_bf *bf, terminal_plus_messag vc_size = s->params->cn_vc_size; break; default: - tw_error(TW_LOC, "Error connection type"); + tw_error(TW_LOC, "Error Connection type"); } switch(scoring) { @@ -1225,7 +1308,7 @@ static int dfp_score_connection(router_state *s, tw_bf *bf, terminal_plus_messag to_subtract += s->queued_count[port]; score -= to_subtract; - if (c_minimality == C_MIN) //the connection maintains the paths minimality - gets a bonus of 2x + if (c_minimality == C_MIN) //the Connection maintains the paths minimality - gets a bonus of 2x score = score * 2; break; } @@ -1308,6 +1391,79 @@ static Connection get_absolute_best_connection_from_conns(router_state *s, tw_bf return conns[best_score_index]; } +//Now returns random selection from tied best connections. +static Connection get_absolute_best_connection_from_conn_set(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, set< Connection > conns) +{ + if (conns.size() == 0) { //passed no connections to this but we got to return something - return negative filled conn to force a break if not caught + Connection bad_conn; + bad_conn.src_gid = -1; + bad_conn.port = -1; + return bad_conn; + } + if (conns.size() == 1) { //no need to compare singular Connection + return (*(conns.begin())); + } + + int num_to_compare = conns.size(); + int scores[num_to_compare]; + vector < Connection > best_conns; + int best_score = INT_MAX; + + set::iterator it; + int count = 0; + for(it = conns.begin(); it != conns.end(); it++) + { + scores[count] = dfp_score_connection(s, bf, msg, lp, *it, C_MIN); + if (scores[count] < best_score) { + best_score = scores[count]; + best_conns.clear(); + best_conns.push_back(*it); + } + else if (scores[count] == best_score) + { + best_conns.push_back(*it); + } + count++; + + } + + assert(best_conns.size() > 0); + + msg->num_rngs++; + return best_conns[tw_rand_integer(lp->rng, 0, best_conns.size()-1)]; +} + +// note that this is somewhat expensive the larger k is in comparison to the total possible +// consider an optimization to implement an efficient shuffle to poll k random sampling instead +// consider an optimization for the default of 2 +static Connection dfp_get_best_from_k_connection_set(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, set< Connection > conns, int k) +{ + if (conns.size() == 0) + { + Connection bad_conn; + bad_conn.src_gid = -1; + bad_conn.port = -1; + return bad_conn; + } + if (conns.size() == 1) + { + return *(conns.begin()); + } + + vector k_conns; + set::iterator it = conns.begin(); + for(int i = 0; i < k; i++) + { + int offset = tw_rand_integer(lp->rng, 0, conns.size()-1); + msg->num_rngs++; + advance(it, offset); + k_conns.push_back(*it); + conns.erase(it); + it = conns.begin(); + } + return get_absolute_best_connection_from_conns(s, bf, msg, lp, k_conns); +} + static vector< Connection > dfp_select_two_connections(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, vector< Connection > conns) { if(conns.size() < 2) { @@ -1408,23 +1564,48 @@ int dragonfly_plus_get_router_type(int router_id, const dragonfly_plus_param *p) return SPINE; } + +//TODO: Fix this for multi planar /* get the router id associated with a given terminal id */ -int dragonfly_plus_get_assigned_router_id(int terminal_id, const dragonfly_plus_param *p) +int dragonfly_plus_get_assigned_router_id(const dragonfly_plus_param *p, int terminal_id, int rail_id) { // currently supports symmetrical bipartite spine/leaf router configurations // first half of routers in a given group are leafs which have terminals // second half of routers in a given group are spines which have no terminals - int num_groups = p->num_groups; // number of groups of routers in the network + int num_groups = p->num_groups; // number of groups of routers in a plane int num_routers = p->num_routers; // num routers per group int num_router_leaf = p->num_router_leaf; // num leaf routers per group int num_cn = p->num_cn; // num compute nodes per leaf router int num_cn_per_group = (num_router_leaf * num_cn); - + int num_planes = p->num_planes; + int num_rails = p->num_rails; + int total_routers = p->total_routers; + int total_terminals = p->total_terminals; + int group_id = terminal_id / num_cn_per_group; + int planar_group_id = group_id % num_groups; int local_router_id = (terminal_id / num_cn) % num_router_leaf; - int router_id = (group_id * num_routers) + local_router_id; + int router_id_on_plane_0 = (planar_group_id * num_routers) + local_router_id; - return router_id; + if (num_planes == 1) + { + if (num_rails == 1) //default behavior + { + return router_id_on_plane_0; + } + else //all rails go to same router, perhaps change this + { + return router_id_on_plane_0; + } + } + else + { + int routers_per_plane = total_routers / num_planes; + if(num_planes == num_rails) + { + return router_id_on_plane_0 + (rail_id * routers_per_plane); + } + } } static void append_to_terminal_plus_message_list(terminal_plus_message_list **thisq, @@ -1493,6 +1674,30 @@ static terminal_plus_message_list *return_tail(terminal_plus_message_list **this return tail; } +static tw_stime* buff_time_storage_create(terminal_state *s) +{ + tw_stime* storage = (tw_stime*)malloc(s->params->num_rails * sizeof(tw_stime)); + return storage; +} + +static void buff_time_storage_delete(void * ptr) +{ + if (ptr) + free(ptr); +} + +static int* int_storage_create(terminal_state *s) +{ + int* storage = (int*)malloc(s->params->num_rails * sizeof(int)); + return storage; +} + +static void int_storage_delete(void * ptr) +{ + if (ptr) + free(ptr); +} + void dragonfly_plus_print_params(const dragonfly_plus_param *p, FILE * st) { if (!st) @@ -1509,16 +1714,21 @@ void dragonfly_plus_print_params(const dragonfly_plus_param *p, FILE * st) fprintf(st,"\tcn_vc_size = %d\n",p->cn_vc_size); fprintf(st,"\tchunk_size = %d\n",p->chunk_size); fprintf(st,"\tnum_cn = %d\n",p->num_cn); + fprintf(st,"\tcn_radix = %d\n",p->cn_radix); fprintf(st,"\tintra_grp_radix = %d\n",p->intra_grp_radix); fprintf(st,"\tnum_qos_levels = %d\n",p->num_qos_levels); fprintf(st,"\tnum_router_spine = %d\n",p->num_router_spine); fprintf(st,"\tnum_router_leaf = %d\n",p->num_router_leaf); fprintf(st,"\tmax_port_score = %ld\n",p->max_port_score); fprintf(st,"\tnum_groups = %d\n",p->num_groups); + fprintf(st,"\ttotal_groups = %d\n",p->total_groups); fprintf(st,"\tvirtual radix = %d\n",p->radix); fprintf(st,"\ttotal_routers = %d\n",p->total_routers); fprintf(st,"\ttotal_terminals = %d\n",p->total_terminals); fprintf(st,"\tnum_global_connections = %d\n",p->num_global_connections); + fprintf(st,"\tnum_injection_queues = %d\n",p->num_injection_queues); + fprintf(st,"\tnum_rails = %d\n",p->num_rails); + fprintf(st,"\tnum_planes = %d\n",p->num_planes); fprintf(st,"\tcn_delay = %.2f\n",p->cn_delay); fprintf(st,"\tlocal_delay = %.2f\n",p->local_delay); fprintf(st,"\tglobal_delay = %.2f\n",p->global_delay); @@ -1691,6 +1901,12 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params routing = PROG_ADAPTIVE; else if (strcmp(routing_str, "fully-prog-adaptive") == 0) routing = FULLY_PROG_ADAPTIVE; + else if (strcmp(routing_str, "smart-prog-adaptive") == 0) + routing = SMART_PROG_ADAPTIVE; + else if (strcmp(routing_str, "smart-minimal") == 0) + routing = SMART_MINIMAL; + else if (strcmp(routing_str, "smart-nonminimal") == 0) + routing = SMART_NON_MINIMAL; else { if(!myRank) fprintf(stderr, "No routing protocol specified, setting to minimal routing\n"); @@ -1755,6 +1971,54 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params p->dest_spine_consider_global_nonmin = false; + rc = configuration_get_value_int(&config, "PARAMS", "num_injection_queues", anno, &p->num_injection_queues); + if(rc) + p->num_injection_queues = 1; + + p->num_rails = 1; + rc = configuration_get_value_int(&config, "PARAMS", "num_rails", anno, &p->num_rails); + if (!rc) { + if (!myRank) + printf("num_rails set to %d\n",p->num_rails); + } + + p->num_planes = 1; + rc = configuration_get_value_int(&config, "PARAMS", "num_planes", anno, &p->num_planes); + if (!rc) { + if (!myRank) + printf("num_planes set to %d\n",p->num_planes); + // tw_error(TW_LOC, "Multi Planar Dragonfly not implemented yet\n"); + } + + p->num_rails_per_plane = p->num_rails / p->num_planes; + if (p->num_rails % p->num_planes != 0) + tw_error(TW_LOC, "Number of rails not evenly divisible by number of planes!\n"); + + char rail_select_str[MAX_NAME_LENGTH]; + rc = configuration_get_value(&config, "PARAMS", "rail_select", anno, rail_select_str, + MAX_NAME_LENGTH); + if(strcmp(rail_select_str, "dedicated") == 0) + p->rail_select = RAIL_DEDICATED; + else if(strcmp(rail_select_str, "congestion")==0) + p->rail_select = RAIL_CONGESTION; + else if(strcmp(rail_select_str, "path")==0) + p->rail_select = RAIL_PATH; + else if(strcmp(rail_select_str, "rand")==0) + p->rail_select = RAIL_RAND; + else { + p->rail_select = RAIL_DEDICATED; + } + if (p->num_rails == 1) + p->rail_select = RAIL_DEDICATED; + if(!myRank) printf("Dragonfly rail selection is %d\n", p->rail_select); + + rc = configuration_get_value_int(&config, "PARAMS", "global_k_picks", anno, &p->global_k_picks); + if(rc) { + p->global_k_picks = 2; + if(!myRank) + fprintf(stderr, "global_k_picks for global adaptive routing not specified, setting to %d\n",p->global_k_picks); + } + /* MM: This should be 2 for dragonfly plus*/ p->num_vcs = 2; @@ -1788,10 +2052,13 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params if (rc) { tw_error(TW_LOC, "\nnum_global_connections per router not specified, abortin..."); } - p->radix = p->intra_grp_radix + p->num_global_connections + - p->num_cn; // TODO this may not be sufficient, radix isn't same for leaf and spine routers - p->total_routers = p->num_groups * p->num_routers; - p->total_terminals = (p->num_groups * p->num_router_leaf) * p->num_cn; + + p->cn_radix = (p->num_cn * p->num_rails) / p->num_planes; //number of CNs per router times number of rails taht each CN has, divided by how many planes those CNs are shared across + p->radix = p->intra_grp_radix + p->num_global_connections + p->cn_radix; + p->total_groups = p->num_groups * p->num_planes; + p->total_routers = p->num_groups * p->num_routers * p->num_planes; + p->total_terminals = ((p->total_groups * p->num_router_leaf) * p->num_cn) / p->num_planes; + p->num_routers_per_plane = p->total_routers / p->num_planes; char scoring_str[MAX_NAME_LENGTH]; configuration_get_value(&config, "PARAMS", "route_scoring_metric", anno, scoring_str, MAX_NAME_LENGTH); @@ -1837,6 +2104,9 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params p->max_port_score = (p->num_vcs * largest_vc_size) + largest_vc_size; //The maximum score that a port can get during the scoring metrics. + //Setup DragonflyNetworkManager + netMan = DragonflyNetworkManager(p->total_routers, p->total_terminals, p->num_routers, p->intra_grp_radix, p->num_global_connections, p->cn_radix, p->num_rails, p->num_planes, max_hops_per_group, max_global_hops_nonminimal); + // read intra group connections, store from a router's perspective // all links to the same router form a vector char intraFile[MAX_NAME_LENGTH]; @@ -1845,16 +2115,16 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params tw_error(TW_LOC, "\nIntra group connections file not specified. Aborting\n"); } - //setup Connection Managers for each router - for(int i = 0; i < p->total_routers; i++) - { - int src_id_global = i; - int src_id_local = i % p->num_routers; - int src_group = i / p->num_routers; + // //setup Connection Managers for each router + // for(int i = 0; i < p->total_routers; i++) + // { + // int src_id_global = i; + // int src_id_local = i % p->num_routers; + // int src_group = i / p->num_routers; - ConnectionManager conman = ConnectionManager(src_id_local, src_id_global, src_group, p->intra_grp_radix, p->num_global_connections, p->num_cn, p->num_routers); - connManagerList.push_back(conman); - } + // DragonflyConnectionManager conman = DragonflyConnectionManager(src_id_local, src_id_global, src_group, p->intra_grp_radix, p->num_global_connections, p->num_cn, p->num_routers, p->num_groups); + // connManagerList.push_back(conman); + // } FILE *groupFile = fopen(intraFile, "rb"); if (!groupFile) @@ -1864,13 +2134,22 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params while (fread(&newLink, sizeof(IntraGroupLink), 1, groupFile) != 0) { int src_id_local = newLink.src; int dest_id_local = newLink.dest; - for(int i = 0; i < p->total_routers; i++) + for(int i = 0; i < p->total_routers; i++) //handles all routers in network, including multi planar { int group_id = i/p->num_routers; if (i % p->num_routers == src_id_local) { - int dest_id_global = group_id * p->num_routers + dest_id_local; - connManagerList[i].add_connection(dest_id_global, CONN_LOCAL); + int planar_id = i / p->num_routers_per_plane; + int dest_gid_global = (group_id * p->num_routers + dest_id_local); + + Link_Info new_link; + new_link.src_gid = i; + new_link.dest_gid = dest_gid_global; + new_link.conn_type = CONN_LOCAL; + new_link.rail_id = planar_id; + netMan.add_link(new_link); + // int dest_id_global = group_id * p->num_routers + dest_id_local; + // connManagerList[i].add_connection(dest_id_global, CONN_LOCAL); } } } @@ -1879,9 +2158,23 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params //terminal assignment! for(int i = 0; i < p->total_terminals; i++) { - int assigned_router_id = dragonfly_plus_get_assigned_router_id(i, p); - int assigned_group_id = assigned_router_id / p->num_routers; - connManagerList[assigned_router_id].add_connection(i, CONN_TERMINAL); + for(int j = 0; j < p->num_rails; j++) + { + int assigned_router_id = dragonfly_plus_get_assigned_router_id(p, i, j); + // int assigned_router_id = (int) i / p->num_cn; + // int assigned_group_id = assigned_router_id / p->num_routers; + Link_Info new_link; + new_link.src_gid = assigned_router_id; + new_link.dest_gid = i; + new_link.conn_type = CONN_TERMINAL; + new_link.rail_id = j; + // printf("R%d <-> T%d P%d\n",new_link.src_gid, new_link.dest_gid, new_link.rail_id); + netMan.add_link(new_link); + // connManagerList[assigned_router_id].add_connection(i, CONN_TERMINAL); + } + // int assigned_router_id = dragonfly_plus_get_assigned_router_id(i, p); + // int assigned_group_id = assigned_router_id / p->num_routers; + // connManagerList[assigned_router_id].add_connection(i, CONN_TERMINAL); } // read inter group connections, store from a router's perspective @@ -1897,37 +2190,77 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params printf("\nTotal routers: %d; total groups: %d \n", p->total_routers, p->num_groups); } - connectionList.resize(p->num_groups); - for (int g = 0; g < connectionList.size(); g++) { - connectionList[g].resize(p->num_groups); - } - InterGroupLink newInterLink; while (fread(&newInterLink, sizeof(InterGroupLink), 1, systemFile) != 0) { - int src_id_global = newInterLink.src; - int src_group_id = src_id_global / p->num_routers; - int dest_id_global = newInterLink.dest; - int dest_group_id = dest_id_global / p->num_routers; - - // printf("[%d -> %d]\n",src_id_global, dest_id_global); - connManagerList[src_id_global].add_connection(dest_id_global, CONN_GLOBAL); - - int r; - for (r = 0; r < connectionList[src_group_id][dest_group_id].size(); r++) { - if (connectionList[src_group_id][dest_group_id][r] == newInterLink.src) - break; + + for(int i = 0; i < p->num_planes; i++) + { + int read_src_id_global = newInterLink.src; + int read_src_group_id = read_src_id_global / p->num_routers; + int read_dest_id_global = newInterLink.dest; + int read_dest_group_id = read_dest_id_global / p->num_routers; + + int mapped_src_gid = read_src_id_global + (i*p->num_routers_per_plane); + int mapped_dest_gid = read_dest_id_global + (i*p->num_routers_per_plane); + + Link_Info new_link; + new_link.src_gid = mapped_src_gid; + new_link.dest_gid = mapped_dest_gid; + new_link.conn_type = CONN_GLOBAL; + new_link.rail_id = i; + // printf("R%d G-> R%d P%d\n",new_link.src_gid, new_link.dest_gid, new_link.rail_id); + netMan.add_link(new_link); + } + } + + //read link failure file + char failureFileName[MAX_NAME_LENGTH]; + failureFileName[0] = '\0'; + + if (strlen(g_nm_link_failure_filepath) == 0) //was this defined already via a command line argument? + { + configuration_get_value(&config, "PARAMS", "link-failure-file", + anno, failureFileName, MAX_NAME_LENGTH); + if (strlen(failureFileName) > 0) { + netMan.enable_link_failures(); } - if (r == connectionList[src_group_id][dest_group_id].size()) { - connectionList[src_group_id][dest_group_id].push_back(newInterLink.src); + } + else + { + strcpy(failureFileName, g_nm_link_failure_filepath); + netMan.enable_link_failures(); + } + + if(netMan.is_link_failures_enabled()) + { + if(!myRank) + printf("\nDragonfly Plus: Link Failures Feature Enabled\n"); + + FILE *failureFile = fopen(failureFileName, "rb"); + if (!failureFile) + tw_error(TW_LOC, "link failure file not found: %s\n",failureFileName); + + if (!myRank) + fprintf(stderr, "Reading link failure file: %s\n", failureFileName); + + Link_Info link; + while (fread(&link, sizeof(Link_Info), 1, failureFile) != 0) { + netMan.add_link_failure_info(link); } } + netMan.solidify_network(); //finalize link failures and burn the network links into the Connection managers + if (DUMP_CONNECTIONS) { - if (!myRank) { - for(int i=0; i < connManagerList.size(); i++) + if(!myRank) { + for (int i = 0; i < p->total_routers; i++) + { + netMan.get_connection_manager_for_router(i).print_connections(); + } + for (int i = 0; i < p->total_terminals; i++) { - connManagerList[i].print_connections(); + netMan.get_connection_manager_for_terminal(i).print_connections(); } } } @@ -1947,7 +2280,7 @@ static void dragonfly_read_config(const char *anno, dragonfly_plus_param *params rc = configuration_get_value_double(&config, "PARAMS", "cn_delay", anno, &p->cn_delay); if (rc) { - p->cn_delay = bytes_to_ns(p->chunk_size, p->cn_bandwidth); + p->cn_delay = bytes_to_ns(p->chunk_size, p->cn_bandwidth*p->num_rails); if(!myRank) fprintf(stderr, "cn_delay not specified, using default calculation: %.2f\n", p->cn_delay); } @@ -2122,7 +2455,7 @@ int get_vcg_from_category(terminal_plus_message * msg) tw_error(TW_LOC, "\n priority needs to be specified with qos_levels > 1 %s", msg->category); } -static int get_term_bandwidth_consumption(terminal_state * s, int qos_lvl) +static int get_term_bandwidth_consumption(terminal_state * s, int rail_id, int qos_lvl) { assert(qos_lvl >= Q_HIGH && qos_lvl <= Q_LOW); @@ -2132,7 +2465,7 @@ static int get_term_bandwidth_consumption(terminal_state * s, int qos_lvl) double max_bw_per_ns = max_bw / (1000.0 * 1000.0 * 1000.0); /* derive maximum bytes that can be transferred during the window */ double max_bytes_per_win = max_bw_per_ns * bw_reset_window; - int percent_bw = (((double)s->qos_data[qos_lvl]) / max_bytes_per_win) * 100; + int percent_bw = (((double)s->qos_data[rail_id][qos_lvl]) / max_bytes_per_win) * 100; // printf("\n At terminal %lf max bytes %d percent %d ", max_bytes_per_win, s->qos_data[qos_lvl], percent_bw); return percent_bw; } @@ -2140,7 +2473,7 @@ static int get_term_bandwidth_consumption(terminal_state * s, int qos_lvl) static int get_rtr_bandwidth_consumption(router_state * s, int qos_lvl, int output_port) { assert(qos_lvl >= Q_HIGH && qos_lvl <= Q_LOW); - assert(output_port < s->params->intra_grp_radix + s->params->num_global_connections + s->params->num_cn); + assert(output_port < s->params->intra_grp_radix + s->params->num_global_connections + s->params->cn_radix); int bandwidth = s->params->cn_bandwidth; if(output_port < s->params->intra_grp_radix) @@ -2171,8 +2504,8 @@ void issue_bw_monitor_event_rc(terminal_state * s, tw_bf * bf, terminal_plus_mes { for(int i = 0; i < num_qos_levels; i++) { - s->qos_data[i] = msg->rc_qos_data[i]; - s->qos_status[i] = msg->rc_qos_status[i]; + s->qos_data[msg->rail_id][i] = msg->rc_qos_data[i]; //rail id of data put into the rc data is the same as the one it's being extracted to. + s->qos_status[msg->rail_id][i] = msg->rc_qos_status[i]; } free(msg->rc_qos_data); @@ -2188,26 +2521,35 @@ void issue_bw_monitor_event(terminal_state * s, tw_bf * bf, terminal_plus_messag msg->num_cll = 0; msg->num_rngs = 0; int num_qos_levels = s->params->num_qos_levels; + int num_rails = s->params->num_rails; //RC data storage start. //Allocate memory here for these pointers that are stored in the events. FREE THESE IN RC OR IN COMMIT_F - msg->rc_qos_data = (unsigned long long *) calloc(num_qos_levels, sizeof(unsigned long long)); - msg->rc_qos_status = (int *) calloc(num_qos_levels, sizeof(int)); + msg->rc_qos_data = (unsigned long long *) calloc(num_rails*num_qos_levels, sizeof(unsigned long long)); + msg->rc_qos_status = (int *) calloc(num_rails*num_qos_levels, sizeof(int)); //store qos data and status into the arrays. Pointers to the arrays are stored in events. - for(int i = 0; i < num_qos_levels; i++) + for(int i = 0; i < num_rails; i++) { - msg->rc_qos_data[i] = s->qos_data[i]; - msg->rc_qos_status[i] = s->qos_status[i]; + for(int j = 0; j < num_qos_levels; j++) + { + *(indexer2d(msg->rc_qos_data, i, j, num_rails, num_qos_levels)) = s->qos_data[i][j]; + *(indexer2d(msg->rc_qos_status, i, j, num_rails, num_qos_levels)) = s->qos_status[i][j]; + } } msg->rc_is_qos_set = 1; //RC data storage end. /* Reset the qos status and bandwidth consumption. */ - for(int i = 0; i < num_qos_levels; i++) + for(int i = 0; i < num_rails; i++) { - s->qos_status[i] = Q_ACTIVE; - s->qos_data[i] = 0; + for(int j = 0; j < num_qos_levels; j++) + { + s->qos_status[j][i] = Q_ACTIVE; + s->qos_data[j][i] = 0; + } + s->busy_time_sample[i] = 0; + s->ross_sample.busy_time_sample[i] = 0; } if(tw_now(lp) > max_qos_monitor) @@ -2281,7 +2623,7 @@ void issue_rtr_bw_monitor_event(router_state *s, tw_bf *bf, terminal_plus_messag int bw_consumed = get_rtr_bandwidth_consumption(s, j, i); #if DEBUG_QOS == 1 - if(dragonfly_rtr_bw_log != NULL) + if(dragonfly_rtr_bw_log != NULL && ROUTER_BW_LOG) { if(s->qos_data[j][k] > 0) { @@ -2323,7 +2665,7 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_plus_message * if(num_qos_levels == 1) { - if(s->terminal_msgs[0] == NULL || ((s->vc_occupancy[0] + s->params->chunk_size) > s->params->cn_vc_size)) + if(s->terminal_msgs[msg->rail_id][0] == NULL || s->vc_occupancy[msg->rail_id][0] + s->params->chunk_size > s->params->cn_vc_size) return -1; else return 0; @@ -2334,9 +2676,9 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_plus_message * /* First make sure the bandwidth consumptions are up to date. */ for(int k = 0; k < num_qos_levels; k++) { - if(s->qos_status[k] != Q_OVERBW) + if(s->qos_status[msg->rail_id][k] != Q_OVERBW) { - bw_consumption[k] = get_term_bandwidth_consumption(s, k); + bw_consumption[k] = get_term_bandwidth_consumption(s, msg->rail_id, k); if(bw_consumption[k] > s->params->qos_bandwidths[k]) { if(k == 0) @@ -2344,7 +2686,7 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_plus_message * else if(k == 1) msg->qos_reset2 = 1; - s->qos_status[k] = Q_OVERBW; + s->qos_status[msg->rail_id][k] = Q_OVERBW; } } } @@ -2352,26 +2694,26 @@ static int get_next_vcg(terminal_state * s, tw_bf * bf, terminal_plus_message * { for(int i = 0; i < num_qos_levels; i++) { - if(s->qos_status[i] == Q_ACTIVE) + if(s->qos_status[msg->rail_id][i] == Q_ACTIVE) { - if(s->terminal_msgs[i] != NULL && ((s->vc_occupancy[i] + s->params->chunk_size) <= s->params->cn_vc_size)) + if(s->terminal_msgs[msg->rail_id][i] != NULL && s->vc_occupancy[msg->rail_id][i] + s->params->chunk_size <= s->params->cn_vc_size) return i; } } } - int next_rr_vcg = (s->last_qos_lvl + 1) % num_qos_levels; + int next_rr_vcg = (s->last_qos_lvl[msg->rail_id] + 1) % num_qos_levels; /* All vcgs are exceeding their bandwidth limits*/ for(int i = 0; i < num_qos_levels; i++) { - if(s->terminal_msgs[i] != NULL && ((s->vc_occupancy[i] + s->params->chunk_size) <= s->params->cn_vc_size)) + if(s->terminal_msgs[msg->rail_id][i] != NULL && s->vc_occupancy[msg->rail_id][i] + s->params->chunk_size <= s->params->cn_vc_size) { bf->c2 = 1; if(msg->last_saved_qos < 0) - msg->last_saved_qos = s->last_qos_lvl; + msg->last_saved_qos = s->last_qos_lvl[msg->rail_id]; - s->last_qos_lvl = next_rr_vcg; + s->last_qos_lvl[msg->rail_id] = next_rr_vcg; return i; } next_rr_vcg = (next_rr_vcg + 1) % num_qos_levels; @@ -2510,29 +2852,42 @@ void terminal_plus_init(terminal_state *s, tw_lp *lp) s->params = &all_params[id]; } + const dragonfly_plus_param * p = s->params; + int num_qos_levels = s->params->num_qos_levels; int num_lps = codes_mapping_get_lp_count(lp_group_name, 1, LP_CONFIG_NM_TERM, s->anno, 0); s->terminal_id = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); - s->router_id = dragonfly_plus_get_assigned_router_id(s->terminal_id, s->params); - // s->router_id=(int)s->terminal_id / (s->params->num_cn); //TODO I think this is where the router that - // the terminal is connected to is specified + s->router_id = (unsigned int*)calloc(p->num_rails, sizeof(unsigned int)); + s->router_lp = (tw_lpid*)calloc(p->num_rails, sizeof(tw_lpid)); + + s->connMan = netMan.get_connection_manager_for_terminal(s->terminal_id); + + + for(i = 0; i < p->num_rails; i++) + { + s->router_id[i] = dragonfly_plus_get_assigned_router_id(s->params,s->terminal_id,i); + num_routers_per_mgrp = codes_mapping_get_lp_count (lp_group_name, 1, "modelnet_dragonfly_plus_router", + NULL, 0); + codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM_ROUT, NULL, 1, s->router_id[i] / num_routers_per_mgrp, s->router_id[i] % num_routers_per_mgrp, &s->router_lp[i]); + } // printf("%d gid is TERMINAL %d with assigned router %d\n",lp->gid,s->terminal_id,s->router_id); - s->terminal_available_time = 0.0; + s->terminal_available_time = (tw_stime*)calloc(p->num_rails, sizeof(tw_stime)); s->packet_counter = 0; s->min_latency = INT_MAX; s->max_latency = 0; + s->link_traffic=(uint64_t*)calloc(p->num_rails, sizeof(uint64_t)); s->finished_msgs = 0; s->finished_chunks = 0; s->finished_packets = 0; s->total_time = 0.0; s->total_msg_size = 0; - s->stalled_chunks = 0; - s->busy_time = 0.0; + s->stalled_chunks = (unsigned long*)calloc(p->num_rails, sizeof(uint64_t)); + s->busy_time = (tw_stime*)calloc(p->num_rails, sizeof(tw_stime)); s->fwd_events = 0; s->rev_events = 0; @@ -2543,44 +2898,62 @@ void terminal_plus_init(terminal_state *s, tw_lp *lp) if(num_qos_levels > 1) s->num_vcs *= num_qos_levels; - /* Whether the virtual channel group is active or over-bw*/ - s->qos_status = (int*)calloc(num_qos_levels, sizeof(int)); - - /* How much data has been transmitted on the virtual channel group within - * the window */ - s->qos_data = (unsigned long long*)calloc(num_qos_levels, sizeof(unsigned long long)); - s->vc_occupancy = (int*)calloc(s->num_vcs, sizeof(int)); + s->vc_occupancy = (int**)calloc(p->num_rails, sizeof(int*)); + s->last_buf_full = (tw_stime*)calloc(p->num_rails, sizeof(tw_stime)); - - for(i = 0; i < num_qos_levels; i++) - { - s->qos_data[i] = 0; - s->qos_status[i] = Q_ACTIVE; - } + s->terminal_length = (int**)calloc(p->num_rails, sizeof(int*)); //1 vc times number of qos levels - for(i = 0; i < s->num_vcs; i++) + for(i = 0; i < p->num_rails; i++) { - s->vc_occupancy[i] = 0; + s->vc_occupancy[i]= (int*)calloc(num_qos_levels, sizeof(int)); + s->terminal_length[i]= (int*)calloc(num_qos_levels, sizeof(int)); } - s->last_qos_lvl = 0; - s->last_buf_full = 0; + s->in_send_loop = (int*)calloc(p->num_rails, sizeof(int)); + s->issueIdle = (int*)calloc(p->num_rails, sizeof(int)); s->rank_tbl = NULL; - s->terminal_msgs = - (terminal_plus_message_list **) calloc(s->num_vcs, sizeof(terminal_plus_message_list *)); - s->terminal_msgs_tail = - (terminal_plus_message_list **) calloc(s->num_vcs, sizeof(terminal_plus_message_list *)); + s->terminal_msgs = + (terminal_plus_message_list***)calloc(p->num_rails, sizeof(terminal_plus_message_list**)); + s->terminal_msgs_tail = + (terminal_plus_message_list***)calloc(p->num_rails, sizeof(terminal_plus_message_list**)); + + /* Whether the virtual channel group is active or over-bw*/ + s->qos_status = (int**)calloc(p->num_rails, sizeof(int*)); + /* How much data has been transmitted on the virtual channel group within + * the window */ + s->qos_data = (int**)calloc(p->num_rails, sizeof(int*)); - for(int i = 0; i < s->num_vcs; i++) + for(i = 0; i < p->num_rails; i++) { - s->terminal_msgs[i] = NULL; - s->terminal_msgs_tail[i] = NULL; + s->in_send_loop[i] = 0; + s->terminal_msgs[i] = (terminal_plus_message_list**)calloc(num_qos_levels, sizeof(terminal_plus_message_list*)); + s->terminal_msgs_tail[i] = (terminal_plus_message_list**)calloc(num_qos_levels, sizeof(terminal_plus_message_list*)); + + for(int j = 0; j < num_qos_levels; j++) + { + s->terminal_msgs[i][j] = NULL; + s->terminal_msgs_tail[i][j] = NULL; + } + + /* Whether the virtual channel group is active or over-bw*/ + s->qos_status[i] = (int*)calloc(num_qos_levels, sizeof(int)); + + /* How much data has been transmitted on the virtual channel group within + * the window */ + s->qos_data[i] = (int*)calloc(num_qos_levels, sizeof(int)); + for(int j = 0; j < num_qos_levels; j++) + { + s->qos_data[i][j] = 0; + s->qos_status[i][j] = Q_ACTIVE; + } } + s->last_qos_lvl = (int*)calloc(p->num_rails, sizeof(int)); + - s->terminal_length = (unsigned long long*)calloc(s->num_vcs, sizeof(unsigned long long)); - s->in_send_loop = 0; - s->issueIdle = 0; + s->ross_sample.busy_time_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); + s->busy_time_ross_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); + s->busy_time_sample = (tw_stime*)calloc(s->params->num_rails, sizeof(tw_stime)); return; } @@ -2618,6 +2991,7 @@ void router_plus_init(router_state *r, tw_lp *lp) p->num_routers, p->total_routers, num_grp_reps * num_routers_per_mgrp); r->router_id = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); + r->plane_id = r->router_id / p->num_routers_per_plane; r->group_id = r->router_id / p->num_routers; // printf("\n Local router id %d global id %d ", r->router_id, lp->gid); @@ -2646,14 +3020,14 @@ void router_plus_init(router_state *r, tw_lp *lp) char rtr_bw_log[128]; sprintf(rtr_bw_log, "router-bw-tracker-%d", g_tw_mynode); - if(dragonfly_rtr_bw_log == NULL) + if(dragonfly_rtr_bw_log == NULL && ROUTER_BW_LOG) { dragonfly_rtr_bw_log = fopen(rtr_bw_log, "w+"); fprintf(dragonfly_rtr_bw_log, "\n router-id time-stamp port-id qos-level bw-consumed qos-status qos-data busy-time"); } #endif - r->connMan = &connManagerList[r->router_id]; + r->connMan = netMan.get_connection_manager_for_router(r->router_id); r->gc_usage = (int *) calloc(p->num_global_connections, sizeof(int)); @@ -2753,7 +3127,8 @@ void router_plus_init(router_state *r, tw_lp *lp) } } - r->connMan->solidify_connections(); + if (!r->connMan.check_is_solidified()) + tw_error(TW_LOC, "Connection Manager not solidified - should be performed after loading topology"); return; } @@ -2807,6 +3182,7 @@ static tw_stime dragonfly_plus_packet_event(model_net_request const *req, msg->pull_size = req->pull_size; msg->magic = terminal_magic_num; msg->msg_start_time = req->msg_start_time; + msg->rail_id = req->queue_offset; //for message app id tracking msg->dfp_src_terminal_id = 0; @@ -2870,19 +3246,34 @@ static void packet_generate_rc(terminal_state *s, tw_bf *bf, terminal_plus_messa int i; for (i = 0; i < num_chunks; i++) { - delete_terminal_plus_message_list(return_tail(s->terminal_msgs, s->terminal_msgs_tail, vcg)); - s->terminal_length[vcg] -= s->params->chunk_size; + delete_terminal_plus_message_list(return_tail(s->terminal_msgs[msg->rail_id], s->terminal_msgs_tail[msg->rail_id], vcg)); + s->terminal_length[msg->rail_id][vcg] -= s->params->chunk_size; } if (bf->c5) { - s->in_send_loop = 0; - } - if (bf->c11) { - s->issueIdle = 0; - s->stalled_chunks--; - if(bf->c8) { - s->last_buf_full = msg->saved_busy_time; - } + s->in_send_loop[msg->rail_id] = 0; } + + int* scs = (int*)rc_stack_pop(s->st); + int* iis = (int*)rc_stack_pop(s->st); + tw_stime* bts = (tw_stime*)rc_stack_pop(s->st); + + for(int j = 0; j < s->params->num_injection_queues; j++) + { + s->last_buf_full[j] = bts[j]; + s->issueIdle[j] = iis[j]; + s->stalled_chunks[j] = scs[j]; + } + buff_time_storage_delete(bts); + int_storage_delete(iis); + int_storage_delete(scs); + + // if (bf->c11) {1 + // s->issueIdle[msg->rail_id] = 0; + // s->stalled_chunks[msg->rail_id]--; + // if(bf->c8) + // s->last_buf_full[msg->rail_id] = msg->saved_busy_time; + // } + struct mn_stats *stat; stat = model_net_find_stats(msg->category, s->dragonfly_stats_array); stat->send_count--; @@ -2900,32 +3291,6 @@ static void packet_generate(terminal_state *s, tw_bf *bf, terminal_plus_message s->packet_gen++; s->total_gen_size += msg->packet_size; - int num_qos_levels = s->params->num_qos_levels; - int vcg = 0; //by default there's only one VC for terminals, VC0. There can be more based on the number of QoS levels - - if (num_qos_levels > 1) { - tw_lpid router_id; - codes_mapping_get_lp_info(lp->gid, lp_group_name, &mapping_grp_id, NULL, &mapping_type_id, NULL, &mapping_rep_id, &mapping_offset); - codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM_ROUT, NULL, 0, s->router_id / num_routers_per_mgrp, s->router_id % num_routers_per_mgrp, &router_id); - - if (s->is_monitoring_bw == 0) { - bf->c1 = 1; - /* Issue an event on both terminal and router to monitor bandwidth */ - msg->num_cll++; - tw_stime bw_ts = bw_reset_window + codes_local_latency(lp); - terminal_plus_message * m; - tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, DRAGONFLY_PLUS, (void**)&m, NULL); - m->type = T_BANDWIDTH; - m->magic = terminal_magic_num; - s->is_monitoring_bw = 1; - tw_event_send(e); - } - - vcg = get_vcg_from_category(msg); - assert(vcg == Q_HIGH || vcg == Q_MEDIUM); - } - assert(vcg < num_qos_levels); - tw_stime ts, nic_ts; assert(lp->gid != msg->dest_terminal_id); @@ -2935,13 +3300,169 @@ static void packet_generate(terminal_state *s, tw_bf *bf, terminal_plus_message uint64_t num_chunks = msg->packet_size / p->chunk_size; double cn_delay = s->params->cn_delay; - int dest_router_id = dragonfly_plus_get_assigned_router_id(msg->dfp_dest_terminal_id, s->params); + + //get rails available: should be from rails known to not be failed + vector< Connection > injection_connections = s->connMan.get_connections_by_type(CONN_INJECTION, false); + if(injection_connections.size() < 1) + tw_error(TW_LOC, "Packet Generation Failure: No non-failed injection connections available on terminal %d\n", s->terminal_id); + + vector< Connection > valid_rails; + if (netMan.is_link_failures_enabled()) + { + for (int i = 0; i < injection_connections.size(); i++) + { + int rail_id = injection_connections[i].rail_or_planar_id; + int dest_router_id = dragonfly_plus_get_assigned_router_id(s->params, msg->dfp_dest_terminal_id, rail_id); + int src_router_id = dragonfly_plus_get_assigned_router_id(s->params, s->terminal_id, rail_id); + int src_group_id = src_router_id / s->params->num_routers; + int dest_group_id = dest_router_id / s->params->num_routers; + + if (isRoutingMinimal(routing)) { + if (src_group_id == dest_group_id) + { + set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,0); //max global hops for local group routing == 0 + if (valid_next_stops.size() > 0) + valid_rails.push_back(injection_connections[i]); + } + else + { + set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,1); //max global hops for local group routing == 0 + if (valid_next_stops.size() > 0) + valid_rails.push_back(injection_connections[i]); + } + } + else + { + // if (src_group_id == dest_group_id) + // { + // set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,0); //max global hops for local group routing == 0 + // if (valid_next_stops.size() > 0) + // valid_rails.push_back(injection_connections[i]); + // } + // else + // { + set valid_next_stops = netMan.get_valid_next_hops_conns(src_router_id, dest_router_id, max_hops_per_group,max_global_hops_nonminimal); //max global hops for local group routing == 0 + if (valid_next_stops.size() > 0) + valid_rails.push_back(injection_connections[i]); + // } + } + } + if (valid_rails.size() < 1) { + tw_error(TW_LOC,"Invalid Connections in Network due to link failures!\n"); + // valid_rails = injection_connections; //TODO will cause problems - deal with + } + } + else + { + valid_rails = injection_connections; + } + + vector< Connection > tied_rails; + + //determine rail + Connection target_rail_connection = valid_rails[0]; + if (valid_rails.size() > 1) + { + bool congestion_fallback = false; + + if (s->params->rail_select == RAIL_DEDICATED) { //then attempt to inject on rail based on the injection queue from the workload + Connection specific_injection_conn = s->connMan.get_connection_on_port(msg->rail_id, true); + if (specific_injection_conn.port == - 1) + tw_error(TW_LOC, "Packet Generation Failure: No Connection on specified rail\n"); + if (specific_injection_conn.is_failed) + congestion_fallback = true; + else + { + target_rail_connection = specific_injection_conn; + } + + } + + if (s->params->rail_select == RAIL_PATH) { + int path_lens[valid_rails.size()]; + int min_len = 99999; + int path_tie = 0; + int index = 0; + vector< Connection >::iterator it = valid_rails.begin(); + for(; it != valid_rails.end(); it++) + { + int rail_id = it->rail_or_planar_id; + int dest_router_id = dragonfly_plus_get_assigned_router_id(s->params, msg->dfp_dest_terminal_id, rail_id); + int src_router_id = dragonfly_plus_get_assigned_router_id(s->params, s->terminal_id, rail_id); + + path_lens[index] = netMan.get_shortest_dist_between_routers(src_router_id, dest_router_id); + if (path_lens[index] < min_len) { + min_len = path_lens[index]; + target_rail_connection = *it; + tied_rails.clear(); + tied_rails.push_back(*it); + path_tie = 0; + } + else if (path_lens[rail_id] == min_len) + { + path_tie = 1; + tied_rails.push_back(*it); + } + index++; + } + + if(path_tie == 1) + { + int rand_sel = tw_rand_integer(lp->rng, 0, tied_rails.size()-1); + msg->num_rngs++; + target_rail_connection = tied_rails[rand_sel]; + } + } + + if(s->params->rail_select == RAIL_RAND) { + int target_rail_sel = tw_rand_integer(lp->rng, 0, valid_rails.size()-1); + target_rail_connection = valid_rails[target_rail_sel]; + msg->num_rngs++; + } + + if(s->params->rail_select == RAIL_CONGESTION || congestion_fallback) { + int min_score = INT_MAX; + int path_tie = 0; + + vector::iterator it = valid_rails.begin(); + for(; it != valid_rails.end(); it++) + { + int sum = 0; + for(int j = 0; j < p->num_qos_levels; j++) + { + int port_no = it->port; + sum += s->vc_occupancy[port_no][j]; + } + if (sum < min_score) { + min_score = sum; + target_rail_connection = *it; + tied_rails.clear(); + tied_rails.push_back(*it); + path_tie = 0; + } + else if (sum == min_score) + { + path_tie = 1; + tied_rails.push_back(*it); + } + } + if (path_tie == 1) + { + int rand_sel = tw_rand_integer(lp->rng, 0, tied_rails.size() -1); + msg->num_rngs++; + target_rail_connection = tied_rails[rand_sel]; + } + } + } + msg->rail_id = target_rail_connection.rail_or_planar_id; + + int dest_router_id = dragonfly_plus_get_assigned_router_id(p, msg->dfp_dest_terminal_id, msg->rail_id); int dest_grp_id = dest_router_id / s->params->num_routers; - int src_grp_id = s->router_id / s->params->num_routers; + int src_grp_id = s->router_id[msg->rail_id] / s->params->num_routers; if(src_grp_id == dest_grp_id) { - if(dest_router_id == s->router_id) + if(dest_router_id == s->router_id[msg->rail_id]) { bf->c2 = 1; num_local_packets_sr++; @@ -2973,16 +3494,44 @@ static void packet_generate(terminal_state *s, tw_bf *bf, terminal_plus_message msg->my_N_hop = 0; msg->my_l_hop = 0; msg->my_g_hop = 0; + msg->my_hops_cur_group = 0; + + //qos stuff + int num_qos_levels = s->params->num_qos_levels; + int vcg = 0; + + if(num_qos_levels > 1) + { + if(s->is_monitoring_bw == 0) + { + bf->c1 = 1; + /* Issue an event on both terminal and router to monitor bandwidth */ + msg->num_cll++; + tw_stime bw_ts = bw_reset_window + codes_local_latency(lp); + terminal_dally_message * m; + tw_event * e = model_net_method_event_new(lp->gid, bw_ts, lp, DRAGONFLY_PLUS, + (void**)&m, NULL); + m->type = T_BANDWIDTH; + m->magic = terminal_magic_num; + s->is_monitoring_bw = 1; + tw_event_send(e); + } + vcg = get_vcg_from_category(msg); + assert(vcg == Q_HIGH || vcg == Q_MEDIUM); + } + assert(vcg < num_qos_levels); + + + + // if(msg->dest_terminal_id == TRACK) + if (msg->packet_ID == LLU(TRACK_PKT) && lp->gid == T_ID) + printf("\n Packet %llu generated at terminal %d dest %llu size %llu num chunks %llu ", msg->packet_ID, + s->terminal_id, LLU(msg->dest_terminal_id), LLU(msg->packet_size), LLU(num_chunks)); - // if(msg->dest_terminal_id == TRACK) - if (msg->packet_ID == LLU(TRACK_PKT) && lp->gid == T_ID) - printf("\n Packet %llu generated at terminal %d dest %llu size %llu num chunks %llu ", msg->packet_ID, - s->terminal_id, LLU(msg->dest_terminal_id), LLU(msg->packet_size), LLU(num_chunks)); - for (int i = 0; i < num_chunks; i++) { terminal_plus_message_list *cur_chunk = (terminal_plus_message_list *) calloc(1, sizeof(terminal_plus_message_list)); - msg->origin_router_id = s->router_id; + msg->origin_router_id = s->router_id[msg->rail_id]; msg->dfp_src_terminal_id = s->terminal_id; init_terminal_plus_message_list(cur_chunk, msg); @@ -3001,40 +3550,54 @@ static void packet_generate(terminal_state *s, tw_bf *bf, terminal_plus_message msg->local_event_size_bytes); } + cur_chunk->msg.rail_id = msg->rail_id; cur_chunk->msg.output_chan = vcg; //By default is 0 but QoS can mean more than just a single VC for terminals cur_chunk->msg.chunk_id = i; - cur_chunk->msg.origin_router_id = s->router_id; - append_to_terminal_plus_message_list(s->terminal_msgs, s->terminal_msgs_tail, vcg, cur_chunk); - s->terminal_length[vcg] += s->params->chunk_size; + cur_chunk->msg.origin_router_id = s->router_id[msg->rail_id]; + append_to_terminal_plus_message_list(s->terminal_msgs[msg->rail_id], s->terminal_msgs_tail[msg->rail_id],vcg, cur_chunk); + s->terminal_length[msg->rail_id][vcg] += s->params->chunk_size; } - if (s->terminal_length[vcg] < s->params->cn_vc_size) { - model_net_method_idle_event(nic_ts, 0, lp); - } - else { - bf->c11 = 1; - s->issueIdle = 1; - s->stalled_chunks++; + tw_stime *bts = buff_time_storage_create(s); //mallocs space to push onto the rc stack -- free'd in rc + int *iis = int_storage_create(s); + int *scs = int_storage_create(s); - //this block was missing from when QOS was added - readded 10-31-19 - if(s->last_buf_full == 0.0) + //TODO: Inspect this and verify that we should be looking at each port always + for(int j=0; jparams->num_injection_queues; j++){ + bts[j] = s->last_buf_full[j]; + iis[j] = s->issueIdle[j]; + scs[j] = s->stalled_chunks[j]; + + if(s->terminal_length[j][vcg] < s->params->cn_vc_size) { - bf->c8 = 1; - msg->saved_busy_time = s->last_buf_full; - /* TODO: Assumes a single vc from terminal to router */ - s->last_buf_full = tw_now(lp); + double dither = .0001 * tw_rand_unif(lp->rng); + msg->num_rngs++; + model_net_method_idle_event2(nic_ts+dither, 0, j, lp); + } + else + { + s->issueIdle[j] = 1; + s->stalled_chunks[j]++; + if(s->last_buf_full[j] == 0.0) + { + s->last_buf_full[j] = tw_now(lp);; + } } } + rc_stack_push(lp, bts, buff_time_storage_delete, s->st); + rc_stack_push(lp, iis, int_storage_delete, s->st); + rc_stack_push(lp, scs, int_storage_delete, s->st); - if (s->in_send_loop == 0) { + if(s->in_send_loop[msg->rail_id] == 0) { bf->c5 = 1; msg->num_cll++; ts = codes_local_latency(lp); terminal_plus_message *m; tw_event *e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_PLUS, (void **) &m, NULL); + m->rail_id = msg->rail_id; m->type = T_SEND; m->magic = terminal_magic_num; - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = 1; tw_event_send(e); } @@ -3056,17 +3619,17 @@ static void packet_send_rc(terminal_state * s, tw_bf * bf, terminal_plus_message int num_qos_levels = s->params->num_qos_levels; if(msg->qos_reset1) - s->qos_status[0] = Q_ACTIVE; + s->qos_status[msg->rail_id][0] = Q_ACTIVE; if(msg->qos_reset2) - s->qos_status[1] = Q_ACTIVE; + s->qos_status[msg->rail_id][1] = Q_ACTIVE; if(msg->last_saved_qos) - s->last_qos_lvl = msg->last_saved_qos; + s->last_qos_lvl[msg->rail_id] = msg->last_saved_qos; if(bf->c1) { - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = 1; if(bf->c3) - s->last_buf_full = msg->saved_busy_time; + s->last_buf_full[msg->rail_id] = msg->saved_busy_time; return; } @@ -3080,11 +3643,11 @@ static void packet_send_rc(terminal_state * s, tw_bf * bf, terminal_plus_message tw_rand_reverse_unif(lp->rng); } int vcg = msg->saved_vc; - s->terminal_available_time = msg->saved_available_time; + s->terminal_available_time[msg->rail_id] = msg->saved_available_time; - s->terminal_length[vcg] += s->params->chunk_size; - /*TODO: MM change this to the vcg */ - s->vc_occupancy[vcg] -= s->params->chunk_size; + s->terminal_length[msg->rail_id][vcg] += s->params->chunk_size; /*TODO: MM change this to the vcg */ + s->vc_occupancy[msg->rail_id][vcg] -= s->params->chunk_size; + s->link_traffic[msg->rail_id]-=s->params->chunk_size; terminal_plus_message_list* cur_entry = (terminal_plus_message_list *)rc_stack_pop(s->st); @@ -3092,21 +3655,21 @@ static void packet_send_rc(terminal_state * s, tw_bf * bf, terminal_plus_message if(cur_entry->msg.packet_size < s->params->chunk_size) data_size = cur_entry->msg.packet_size % s->params->chunk_size; - s->qos_data[vcg] -= data_size; + s->qos_data[msg->rail_id][vcg] -= data_size; - prepend_to_terminal_plus_message_list(s->terminal_msgs, - s->terminal_msgs_tail, vcg, cur_entry); + prepend_to_terminal_plus_message_list(s->terminal_msgs[msg->rail_id], + s->terminal_msgs_tail[msg->rail_id], vcg, cur_entry); if(bf->c4) { - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = 1; } if (bf->c5) { - s->issueIdle = 1; + s->issueIdle[msg->rail_id] = 1; if (bf->c6) { - s->busy_time = msg->saved_total_time; - s->last_buf_full = msg->saved_busy_time; - s->busy_time_sample = msg->saved_sample_time; - s->ross_sample.busy_time_sample = msg->saved_sample_time; - s->busy_time_ross_sample = msg->saved_busy_time_ross; + s->busy_time[msg->rail_id] = msg->saved_total_time; + s->last_buf_full[msg->rail_id] = msg->saved_busy_time; + s->busy_time_sample[msg->rail_id] = msg->saved_sample_time; + s->ross_sample.busy_time_sample[msg->rail_id] = msg->saved_sample_time; + s->busy_time_ross_sample[msg->rail_id] = msg->saved_busy_time_ross; } } return; @@ -3130,22 +3693,23 @@ static void packet_send(terminal_state *s, tw_bf *bf, terminal_plus_message *msg vcg = get_next_vcg(s, bf, msg, lp); - /* For a terminal to router connection, there would be as many VCGs as number + /* For a terminal to router Connection, there would be as many VCGs as number * of VCs*/ if(vcg == -1) { bf->c1 = 1; - s->in_send_loop = 0; - if(!s->last_buf_full) { + s->in_send_loop[msg->rail_id] = 0; + if(!s->last_buf_full[msg->rail_id]) + { bf->c3 = 1; - msg->saved_busy_time = s->last_buf_full; - s->last_buf_full = tw_now(lp); + msg->saved_busy_time = s->last_buf_full[msg->rail_id]; + s->last_buf_full[msg->rail_id] = tw_now(lp); } return; } msg->saved_vc = vcg; - terminal_plus_message_list* cur_entry = s->terminal_msgs[vcg]; + terminal_plus_message_list* cur_entry = s->terminal_msgs[msg->rail_id][vcg]; int data_size = s->params->chunk_size; uint64_t num_chunks = cur_entry->msg.packet_size / s->params->chunk_size; if (cur_entry->msg.packet_size < s->params->chunk_size) @@ -3157,22 +3721,18 @@ static void packet_send(terminal_state *s, tw_bf *bf, terminal_plus_message *msg delay = bytes_to_ns(cur_entry->msg.packet_size % s->params->chunk_size, s->params->cn_bandwidth); } - s->qos_data[vcg] += data_size; + s->qos_data[msg->rail_id][vcg] += data_size; - msg->saved_available_time = s->terminal_available_time; + msg->saved_available_time = s->terminal_available_time[msg->rail_id]; msg->num_rngs++; ts = g_tw_lookahead + delay + tw_rand_unif(lp->rng); - s->terminal_available_time = maxd(s->terminal_available_time, tw_now(lp)); - s->terminal_available_time += ts; + s->terminal_available_time[msg->rail_id] = maxd(s->terminal_available_time[msg->rail_id], tw_now(lp)); + s->terminal_available_time[msg->rail_id] += ts; - ts = s->terminal_available_time - tw_now(lp); - // TODO: be annotation-aware - codes_mapping_get_lp_info(lp->gid, lp_group_name, &mapping_grp_id, NULL, &mapping_type_id, NULL, - &mapping_rep_id, &mapping_offset); - codes_mapping_get_lp_id(lp_group_name, LP_CONFIG_NM_ROUT, NULL, 1, s->router_id / num_routers_per_mgrp, - s->router_id % num_routers_per_mgrp, &router_id); + ts = s->terminal_available_time[msg->rail_id] - tw_now(lp); + router_id = s->router_lp[msg->rail_id]; // printf("\n Local router id %d global router id %d ", s->router_id, router_id); // we are sending an event to the router, so no method_event here void *remote_event; @@ -3184,13 +3744,14 @@ static void packet_send(terminal_state *s, tw_bf *bf, terminal_plus_message *msg m->type = R_ARRIVE; m->src_terminal_id = lp->gid; + m->rail_id = msg->rail_id; m->vc_index = vcg; m->last_hop = TERMINAL; m->magic = router_magic_num; m->path_type = -1; m->local_event_size_bytes = 0; m->intm_rtr_id = -1; - m->intm_group_id = -1; + m->intm_grp_id = -1; m->dfp_upward_channel_flag = 0; tw_event_send(e); @@ -3206,10 +3767,11 @@ static void packet_send(terminal_state *s, tw_bf *bf, terminal_plus_message *msg } // s->packet_counter++; - s->vc_occupancy[vcg] += s->params->chunk_size; - cur_entry = return_head(s->terminal_msgs, s->terminal_msgs_tail, vcg); + s->vc_occupancy[msg->rail_id][vcg] += s->params->chunk_size; + cur_entry = return_head(s->terminal_msgs[msg->rail_id], s->terminal_msgs_tail[msg->rail_id], vcg); rc_stack_push(lp, cur_entry, delete_terminal_plus_message_list, s->st); - s->terminal_length[vcg] -= s->params->chunk_size; + s->terminal_length[msg->rail_id][vcg] -= s->params->chunk_size; + s->link_traffic[msg->rail_id] += s->params->chunk_size; int next_vcg = 0; @@ -3218,42 +3780,44 @@ static void packet_send(terminal_state *s, tw_bf *bf, terminal_plus_message *msg cur_entry = NULL; if(next_vcg >= 0) - cur_entry = s->terminal_msgs[next_vcg]; + cur_entry = s->terminal_msgs[msg->rail_id][next_vcg]; /* if there is another packet inline then schedule another send event */ - if (cur_entry != NULL && s->vc_occupancy[next_vcg] + s->params->chunk_size <= s->params->cn_vc_size) { + if (cur_entry != NULL && s->vc_occupancy[msg->rail_id][next_vcg] + s->params->chunk_size <= s->params->cn_vc_size) { terminal_plus_message *m_new; msg->num_rngs++; ts += tw_rand_unif(lp->rng); e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_PLUS, (void **) &m_new, NULL); m_new->type = T_SEND; + m_new->rail_id = msg->rail_id; m_new->magic = terminal_magic_num; tw_event_send(e); } else { /* If not then the LP will wait for another credit or packet generation */ bf->c4 = 1; - s->in_send_loop = 0; + s->in_send_loop[msg->rail_id] = 0; } - if (s->issueIdle) { + if(s->issueIdle[msg->rail_id]) { bf->c5 = 1; - s->issueIdle = 0; + s->issueIdle[msg->rail_id] = 0; msg->num_rngs++; ts += tw_rand_unif(lp->rng); - model_net_method_idle_event(ts, 0, lp); + model_net_method_idle_event2(ts, 0, msg->rail_id, lp); - if (s->last_buf_full > 0.0) { + if(s->last_buf_full[msg->rail_id] > 0.0) + { bf->c6 = 1; - msg->saved_total_time = s->busy_time; - msg->saved_busy_time = s->last_buf_full; - msg->saved_sample_time = s->busy_time_sample; - - s->busy_time += (tw_now(lp) - s->last_buf_full); - s->busy_time_sample += (tw_now(lp) - s->last_buf_full); - s->ross_sample.busy_time_sample += (tw_now(lp) - s->last_buf_full); - msg->saved_busy_time_ross = s->busy_time_ross_sample; - s->busy_time_ross_sample += (tw_now(lp) - s->last_buf_full); - s->last_buf_full = 0.0; + msg->saved_total_time = s->busy_time[msg->rail_id]; + msg->saved_busy_time = s->last_buf_full[msg->rail_id]; + msg->saved_sample_time = s->busy_time_sample[msg->rail_id]; + + s->busy_time[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + s->busy_time_sample[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + s->ross_sample.busy_time_sample[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + msg->saved_busy_time_ross = s->busy_time_ross_sample[msg->rail_id]; + s->busy_time_ross_sample[msg->rail_id] += (tw_now(lp) - s->last_buf_full[msg->rail_id]); + s->last_buf_full[msg->rail_id] = 0.0; } } return; @@ -3386,6 +3950,16 @@ static void packet_arrive(terminal_state *s, tw_bf *bf, terminal_plus_message *m // NIC aggregation - should this be a separate function? // Trigger an event on receiving server + if(isRoutingMinimal(routing) && msg->my_N_hop > 4) + { + printf("TERMINAL RECEIVED A NONMINIMAL LENGTH PACKET\n"); + } + if(isRoutingMinimal(routing) && msg->my_g_hop > 1) + { + printf("TERMINAL RECEIVED A DOUBLE GLOBAL HOP PACKET\n"); + } + // printf("%d\n",msg->my_g_hop); + if (msg->my_N_hop > s->params->max_hops_notify) { printf("Terminal received a packet with %d hops! (Notify on > than %d)\n",msg->my_N_hop, s->params->max_hops_notify); @@ -3440,6 +4014,7 @@ static void packet_arrive(terminal_state *s, tw_bf *bf, terminal_plus_message *m buf_e = model_net_method_event_new(msg->intm_lp_id, ts, lp, DRAGONFLY_PLUS_ROUTER, (void **) &buf_msg, NULL); buf_msg->magic = router_magic_num; + buf_msg->rail_id = msg->rail_id; buf_msg->vc_index = msg->vc_index; buf_msg->output_chan = msg->output_chan; buf_msg->type = R_BUFFER; @@ -3463,7 +4038,7 @@ static void packet_arrive(terminal_state *s, tw_bf *bf, terminal_plus_message *m assert(lp->gid != msg->src_terminal_id); // Verify that the router that send the packet to this terminal is the router assigned to this terminal - int dest_router_id = dragonfly_plus_get_assigned_router_id(s->terminal_id, s->params); + int dest_router_id = dragonfly_plus_get_assigned_router_id(s->params, s->terminal_id, msg->rail_id); int received_from_rel_id = codes_mapping_get_lp_relative_id(msg->intm_lp_id,0,0); assert(dest_router_id == received_from_rel_id); @@ -3603,9 +4178,9 @@ static void terminal_buf_update_rc(terminal_state *s, tw_bf *bf, terminal_plus_m if(num_qos_levels > 1) vcg = get_vcg_from_category(msg); - s->vc_occupancy[vcg] += s->params->chunk_size; + s->vc_occupancy[msg->rail_id][vcg] += s->params->chunk_size; if (bf->c1) { - s->in_send_loop = 0; + s->in_send_loop[msg->rail_id] = 0; } return; } @@ -3625,15 +4200,16 @@ static void terminal_buf_update(terminal_state *s, tw_bf *bf, terminal_plus_mess msg->num_cll++; tw_stime ts = codes_local_latency(lp); - s->vc_occupancy[vcg] -= s->params->chunk_size; + s->vc_occupancy[msg->rail_id][vcg] -= s->params->chunk_size; - if (s->in_send_loop == 0 && s->terminal_msgs[vcg] != NULL) { + if(s->in_send_loop[msg->rail_id] == 0 && s->terminal_msgs[msg->rail_id][vcg] != NULL) { terminal_plus_message *m; bf->c1 = 1; tw_event *e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_PLUS, (void **) &m, NULL); + m->rail_id = msg->rail_id; m->type = T_SEND; m->magic = terminal_magic_num; - s->in_send_loop = 1; + s->in_send_loop[msg->rail_id] = 1; tw_event_send(e); } return; @@ -3652,8 +4228,15 @@ void dragonfly_plus_terminal_final(terminal_state *s, tw_lp *lp) if (s->terminal_id == 0) { written += sprintf(s->output_buf + written, "# Format < dest_type> \n"); } - written += sprintf(s->output_buf + written, "%u %s %u %s %s %llu %lf %lu\n", - s->terminal_id, "T", s->router_id, "R", "CN", LLU(s->total_msg_size), s->busy_time, s->stalled_chunks); + // written += sprintf(s->output_buf + written, "%u %s %u %s %s %llu %lf %lu\n", + // s->terminal_id, "T", s->router_id, "R", "CN", LLU(s->total_msg_size), s->busy_time, s->stalled_chunks); + + for(int i = 0; i < s->params->num_rails; i++) + { + //since LLU(s->total_msg_size) is total message size a terminal received from a router so source is router and destination is terminal + written += sprintf(s->output_buf + written, "%u %s %u %s %s %llu %lf %lu\n", + s->terminal_id, "T",s->router_id[i], "R","CN", LLU(s->link_traffic[i]), s->busy_time[i], s->stalled_chunks[i]); + } lp_io_write(lp->gid, (char*)"dragonfly-plus-local-link-stats", written, s->output_buf); @@ -3676,12 +4259,17 @@ void dragonfly_plus_terminal_final(terminal_state *s, tw_lp *lp) written = 0; if(s->terminal_id == 0) { - written += sprintf(s->output_buf2 + written, "# Format <# Packets finished> \n"); + written += sprintf(s->output_buf2 + written, "# Format <# Packets finished> \n"); } + + tw_stime avg_busy_time = 0; + for(int i = 0; i < s->params->num_rails; i++) + avg_busy_time += s->busy_time[i]; + avg_busy_time = avg_busy_time / s->params->num_rails; + written += sprintf(s->output_buf2 + written, "%llu %u %d %llu %lf %lf %lf %ld %lf %lf\n", LLU(lp->gid), s->terminal_id, s->total_gen_size, LLU(s->total_msg_size), s->total_time/s->finished_chunks, s->max_latency, s->min_latency, - s->finished_packets, (double)s->total_hops/s->finished_chunks, s->busy_time); - + s->finished_packets, (double)s->total_hops/s->finished_chunks, avg_busy_time); // written = 0; // written += sprintf(s->output_buf2 + written, "%llu %u %lf %lf %lf %lf %ld %lf\n", @@ -3710,8 +4298,11 @@ void dragonfly_plus_terminal_final(terminal_state *s, tw_lp *lp) // lp_io_write(lp->gid, (char *) "dragonfly-msg-stats", written, s->output_buf); - if (s->terminal_msgs[0] != NULL) + for(int i = 0; i < s->params->num_rails; i++) + { + if(s->terminal_msgs[i][0] != NULL) printf("[%llu] leftover terminal messages \n", LLU(lp->gid)); + } // if(s->packet_gen != s->packet_fin) // printf("\n generated %d finished %d ", s->packet_gen, s->packet_fin); @@ -3720,6 +4311,7 @@ void dragonfly_plus_terminal_final(terminal_state *s, tw_lp *lp) qhash_finalize(s->rank_tbl); rc_stack_destroy(s->st); + //TODO FREE THESE CORRECTLY free(s->vc_occupancy); free(s->terminal_msgs); free(s->terminal_msgs_tail); @@ -3727,34 +4319,9 @@ void dragonfly_plus_terminal_final(terminal_state *s, tw_lp *lp) void dragonfly_plus_router_final(router_state *s, tw_lp *lp) { - // int max_gc_usage = 0; - // int min_gc_usage = INT_MAX; - - // int running_sum = 0; - // for(int i = 0; i < s->params->num_global_connections; i++) - // { - // int gc_val = s->gc_usage[i]; - // running_sum += gc_val; - - // if (gc_val > max_gc_usage) - // max_gc_usage = gc_val; - // if (gc_val < min_gc_usage) - // min_gc_usage = gc_val; - // } - // double mean_gc_usage = (double) running_sum / (double) s->params->num_global_connections; - - // if (s->dfp_router_type == SPINE) { - // printf("Router %d in group %d: Min GC Usage= %d Max GC Usage= %d Mean GC Usage= %.2f", s->router_id, s->router_id / s->params->num_routers, min_gc_usage, max_gc_usage, mean_gc_usage); - // printf("\t["); - // for(int i = 0; i < s->params->num_global_connections; i++) - // { - // printf("%d ",s->gc_usage[i]); - // } - // printf("]\n"); - // } #if DEBUG_QOS - if(s->router_id == 0) + if(s->router_id == 0 && ROUTER_BW_LOG) fclose(dragonfly_rtr_bw_log); #endif @@ -3776,14 +4343,17 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) const dragonfly_plus_param *p = s->params; int written = 0; //local link - int written1 = 0; //global link int written2 = 0; //msg app id rec int src_rel_id = s->router_id % p->num_routers; int local_grp_id = s->router_id / p->num_routers; int total_packet_verify = 0; - vector< Connection > my_local_links = s->connMan->get_connections_by_type(CONN_LOCAL); + // if (s->router_id == 0) { + // written += sprintf(s->output_buf + written, "# Format || < dest_type> , "); + // } + + vector< Connection > my_local_links = s->connMan.get_connections_by_type(CONN_LOCAL,true); vector< Connection >::iterator it = my_local_links.begin(); for(; it != my_local_links.end(); it++) @@ -3796,22 +4366,15 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) "R", dest_rtr_id, "R", - "G", + "L", LLU(s->link_traffic[port_no]), s->busy_time[port_no], s->stalled_chunks[port_no]); } - sprintf(s->output_buf + written, "\n"); - lp_io_write(lp->gid, (char*)"dragonfly-plus-local-link-stats", written, s->output_buf); - - vector< Connection > my_global_links = s->connMan->get_connections_by_type(CONN_GLOBAL); + vector< Connection > my_global_links = s->connMan.get_connections_by_type(CONN_GLOBAL,true); it = my_global_links.begin(); - if (s->router_id == 0) { - written1 += sprintf(s->output_buf2 + written1, "# Format || < dest_type> , "); - } - for(; it != my_global_links.end(); it++) { int dest_rtr_id = it->dest_gid; @@ -3819,7 +4382,7 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) int port_no = it->port; assert(port_no >= 0 && port_no < p->radix); assert(dragonfly_plus_get_router_type(dest_rtr_id, p) == SPINE); - written1 += sprintf(s->output_buf + written1, "\n%d %s G%d || %d %s G%d, %s %llu %lf %lu", + written += sprintf(s->output_buf + written, "\n%d %s G%d || %d %s G%d, %s %llu %lf %lu", s->router_id, "R", s->group_id, @@ -3832,8 +4395,25 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) s->stalled_chunks[port_no]); } - sprintf(s->output_buf2 + written1, "\n"); - lp_io_write(lp->gid, (char*)"dragonfly-plus-global-link-stats", written1, s->output_buf2); + vector< Connection > my_terminal_links = s->connMan.get_connections_by_type(CONN_TERMINAL,true); + it = my_terminal_links.begin(); + for(; it != my_terminal_links.end(); it++) + { + int dest_term_id = it->dest_gid; + int port_no = it->port; + written += sprintf(s->output_buf + written, "\n%d %s %d %s %s %llu %lf %lu", + s->router_id, + "R", + dest_term_id, + "T", + "CN", + LLU(s->link_traffic[port_no]), + s->busy_time[port_no], + s->stalled_chunks[port_no]); + } + + sprintf(s->output_buf + written, "\n"); + lp_io_write(lp->gid, (char*)"dragonfly-plus-link-stats", written, s->output_buf); // I/O for couting of msg app id // wirtten2 + buf4 rec @@ -3888,7 +4468,7 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) // written += sprintf(s->output_buf + written, "\n%s %llu %d %d", router_type, LLU(lp->gid), s->router_id / p->num_routers, s->router_id % p->num_routers); // for (int d = 0; d < p->radix; d++) { // bool printed_hyphen = false; - // ConnectionType port_type = s->connMan->get_port_type(d); + // ConnectionType port_type = s->connMan.get_port_type(d); // if (port_type == 0) { // written += sprintf(s->output_buf + written, " -"); @@ -3911,7 +4491,7 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) // for (int d = 0; d < p->radix; d++) { // bool printed_hyphen = false; - // ConnectionType port_type = s->connMan->get_port_type(d); + // ConnectionType port_type = s->connMan.get_port_type(d); // if (port_type == 0) { // written += sprintf(s->output_buf2 + written, " -"); @@ -3931,119 +4511,76 @@ void dragonfly_plus_router_final(router_state *s, tw_lp *lp) // } } -static Connection do_dfp_routing(router_state *s, - tw_bf *bf, - terminal_plus_message *msg, - tw_lp *lp, - int fdest_router_id) +static Connection do_dfp_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) { - int my_router_id = s->router_id; int my_group_id = s->router_id / s->params->num_routers; int fdest_group_id = fdest_router_id / s->params->num_routers; int origin_group_id = msg->origin_router_id / s->params->num_routers; bool in_intermediate_group = (my_group_id != origin_group_id) && (my_group_id != fdest_group_id); - Connection nextStopConn; //the connection that we will forward the packet to - - //----------- DESTINATION LOCAL GROUP ROUTING -------------- - if (my_router_id == fdest_router_id) { - vector< Connection > poss_next_stops = s->connMan->get_connections_to_gid(msg->dfp_dest_terminal_id, CONN_TERMINAL); - if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "Destination Router: No connection to destination terminal\n"); - Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); - return best_min_conn; - } - else if (my_group_id == fdest_group_id) { //then we just route minimally - vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); - if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "DEAD END WHEN ROUTING LOCALLY - My Router ID: %d FDest Router ID: %d\n", my_router_id, fdest_router_id); - - Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); - return best_min_conn; - } - //------------ END DESTINATION LOCAL GROUP ROUTING --------- - // from here we can assume that we are not in the destination group - - - if (isRoutingAdaptive(routing)) { - if (routing == PROG_ADAPTIVE) - nextStopConn = do_dfp_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); - else if (routing == FULLY_PROG_ADAPTIVE){ - nextStopConn = do_dfp_FPAR(s, bf, msg, lp, fdest_router_id); - } - return nextStopConn; - } - - else if (isRoutingMinimal(routing)) { - vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); - if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "MINIMAL DEAD END\n"); - - // int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() -1 ); - // return poss_next_stops[rand_sel]; - - ConnectionType conn_type = poss_next_stops[0].conn_type; - Connection best_min_conn; - if (conn_type == CONN_GLOBAL) { - msg->num_rngs++; - int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() -1); - return poss_next_stops[rand_sel]; - } - else - best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //gets absolute best - return best_min_conn; - } - - else { //routing algorithm is specified in routing - bool route_to_fdest = false; - if (routing == NON_MINIMAL_LEAF) { - if (msg->dfp_upward_channel_flag == 1) //we only route to minimal if this flag is true, otherwise we keep routing nonminimally - route_to_fdest = true; - - else if (s->dfp_router_type == LEAF) { - if (in_intermediate_group) { //then we are the intermediate router - msg->dfp_upward_channel_flag = 1; - route_to_fdest = true; - } - } - } - else if (routing == NON_MINIMAL_SPINE) { - tw_error(TW_LOC, "nonminimal spine routing not yet supported"); - } - - vector< Connection > poss_min_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); - vector< Connection > poss_intm_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, poss_min_next_stops, fdest_router_id); - - - vector< Connection > poss_next_stops; - if (route_to_fdest) { - poss_next_stops = poss_min_next_stops; + if (!isRoutingSmart(routing)) + { + //----------- DESTINATION LOCAL GROUP ROUTING -------------- + if (my_router_id == fdest_router_id) { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfp_dest_terminal_id, CONN_TERMINAL); if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "Dead end when finding stops to fdest router"); + tw_error(TW_LOC, "Destination Router: No Connection to destination terminal\n"); + + Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_min_conn; } - else { //then we need to be going toward the intermediate router - msg->path_type = NON_MINIMAL; - poss_next_stops = poss_intm_next_stops; + else if (my_group_id == fdest_group_id) { //then we just route minimally + vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); if (poss_next_stops.size() < 1) - tw_error(TW_LOC, "Dead end when finding stops to intermediate router"); + tw_error(TW_LOC, "DEAD END WHEN ROUTING LOCALLY - My Router ID: %d FDest Router ID: %d (origin router ID: %d)\n", my_router_id, fdest_router_id, msg->origin_router_id); + + Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_min_conn; } + //------------ END DESTINATION LOCAL GROUP ROUTING --------- + // from here we can assume that we are not in the destination group - ConnectionType conn_type = poss_next_stops[0].conn_type; //should all be the same - - Connection best_conn; - if (conn_type == CONN_GLOBAL) - best_conn = get_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //pick 2 randomly and pick best from those - else - best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //pick absolute best from poss_next_stops + if(msg->last_hop == TERMINAL) //This is used by dfdally_nonminimal_routing and dfdally_prog_adaptive_routing + { + if (msg->intm_grp_id == -1) + dfp_select_intermediate_group(s, bf, msg, lp, fdest_router_id); + } + } - if (best_conn.port == -1) - tw_error(TW_LOC, "Get best connection returned a bad connection"); - - return best_conn; + Connection next_stop_conn; + switch (routing) + { + case MINIMAL: + next_stop_conn = dfp_minimal_routing(s, bf, msg, lp, fdest_router_id); + break; + case NON_MINIMAL_LEAF: + next_stop_conn = dfp_nonminimal_leaf_routing(s, bf, msg, lp, fdest_router_id); + break; + case NON_MINIMAL_SPINE: + tw_error(TW_LOC, "Non Minimal Spine Routing not implemented for validity concerns\n"); + break; + case PROG_ADAPTIVE: + next_stop_conn = dfp_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); + break; + case FULLY_PROG_ADAPTIVE: + next_stop_conn = dfp_fully_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); + break; + case SMART_MINIMAL: + next_stop_conn = dfp_smart_minimal_routing(s, bf, msg, lp, fdest_router_id); + break; + case SMART_NON_MINIMAL: + next_stop_conn = dfp_smart_nonminimal_routing(s, bf, msg, lp, fdest_router_id); + break; + case SMART_PROG_ADAPTIVE: + next_stop_conn = dfp_smart_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); + break; + default: + tw_error(TW_LOC, "DFP Routing Error: No valid routing algorithm specified\n"); + break; } - tw_error(TW_LOC, "do_dfp_routing(): No route chosen!\n"); + return next_stop_conn; } static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp) @@ -4066,7 +4603,7 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_plu catch (...) { tw_error(TW_LOC, "\nRouter Receipt Verify: Codes Mapping Get LP Rel ID Failure - Terminal"); } - has_valid_connection = s->connMan->is_connected_to_by_type(src_term_rel_id, CONN_TERMINAL); + has_valid_connection = s->connMan.is_connected_to_by_type(src_term_rel_id, CONN_TERMINAL); } else if (msg->last_hop == LOCAL) { @@ -4077,8 +4614,8 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_plu tw_error(TW_LOC, "\nRouter Receipt Verify: Codes Mapping Get LP Rel ID Failure - Local"); } - int rel_loc_id = rel_id % s->params->num_routers; - has_valid_connection = s->connMan->is_connected_to_by_type(rel_loc_id, CONN_LOCAL); + // int rel_loc_id = rel_id % s->params->num_routers; + has_valid_connection = s->connMan.is_connected_to_by_type(rel_id, CONN_LOCAL); } else if (msg->last_hop == GLOBAL) { @@ -4088,7 +4625,7 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_plu catch (...) { tw_error(TW_LOC, "\nRouter Receipt Verify: Codes Mapping Get LP Rel ID Failure - Global"); } - has_valid_connection = s->connMan->is_connected_to_by_type(rel_id, CONN_GLOBAL); + has_valid_connection = s->connMan.is_connected_to_by_type(rel_id, CONN_GLOBAL); } else { @@ -4097,9 +4634,9 @@ static void router_verify_valid_receipt(router_state *s, tw_bf *bf, terminal_plu if (!has_valid_connection){ if (msg->last_hop == TERMINAL) - printf("ERROR: Router ID %d has no connection to Terminal %d but received a message from it!",s->router_id, src_term_rel_id); + printf("ERROR: Router ID %d has no Connection to Terminal %d but received a message from it!",s->router_id, src_term_rel_id); else - printf("ERROR: Router ID %d has no connection to Router %d but received a message from it!",s->router_id, rel_id); + printf("ERROR: Router ID %d has no Connection to Router %d but received a message from it!",s->router_id, rel_id); } assert(has_valid_connection); } @@ -4150,6 +4687,7 @@ static void router_credit_send(router_state *s, terminal_plus_message *msg, tw_l buf_msg->magic = router_magic_num; } + buf_msg->rail_id = msg->rail_id; buf_msg->origin_router_id = s->router_id; if (sq == -1) { buf_msg->vc_index = msg->vc_index; @@ -4174,7 +4712,7 @@ static void router_packet_receive_rc(router_state *s, tw_bf *bf, terminal_plus_m int output_port = msg->saved_vc; int output_chan = msg->saved_channel; - int dest_gid = msg->dfp_dest_terminal_id / (s->params->total_terminals / s->params->num_groups); + int dest_gid = msg->dfp_dest_terminal_id / (s->params->total_terminals / s->params->total_groups); int inter_group_transmit = 0; //rc for msg app id counting @@ -4263,7 +4801,7 @@ static void router_packet_receive(router_state *s, tw_bf *bf, terminal_plus_mess //If spine router, count how many packets I have received & identify their app id msg->last_received_time = tw_now(lp); - int fdest_group_id = msg->dfp_dest_terminal_id / (s->params->total_terminals / s->params->num_groups); + int fdest_group_id = msg->dfp_dest_terminal_id / (s->params->total_terminals / s->params->total_groups); int inter_group_transmit = 0; if(fdest_group_id != s->group_id) inter_group_transmit = 1; @@ -4283,7 +4821,7 @@ static void router_packet_receive(router_state *s, tw_bf *bf, terminal_plus_mess int next_stop = -1, output_port = -1, output_chan = -1, adap_chan = -1; int dfp_dest_terminal_id = msg->dfp_dest_terminal_id; - int dest_router_id = dragonfly_plus_get_assigned_router_id(dfp_dest_terminal_id, s->params); + int dest_router_id = dragonfly_plus_get_assigned_router_id(s->params, msg->dfp_dest_terminal_id, s->plane_id); // int dest_router_id = codes_mapping_get_lp_relative_id(msg->dest_terminal_id, 0, 0) / s->params->num_cn; int local_grp_id = s->router_id / s->params->num_routers; int src_grp_id = msg->origin_router_id / s->params->num_routers; @@ -4303,8 +4841,8 @@ static void router_packet_receive(router_state *s, tw_bf *bf, terminal_plus_mess Connection next_stop_conn = do_dfp_routing(s, bf, &(cur_chunk->msg), lp, dest_router_id); msg->num_rngs += (cur_chunk->msg).num_rngs; //make sure we're counting the rngs called during do_dfp_routing() - if (s->connMan->is_any_connection_to(next_stop_conn.dest_gid) == false) - tw_error(TW_LOC, "Router %d does not have a connection to chosen destination %d\n", s->router_id, next_stop_conn.dest_gid); + if (s->connMan.is_any_connection_to(next_stop_conn.dest_gid) == false) + tw_error(TW_LOC, "Router %d does not have a Connection to chosen destination %d\n", s->router_id, next_stop_conn.dest_gid); output_port = next_stop_conn.port; @@ -4338,13 +4876,17 @@ static void router_packet_receive(router_state *s, tw_bf *bf, terminal_plus_mess assert(output_chan < vcs_per_qos); output_chan = output_chan + (vcg * vcs_per_qos); - ConnectionType port_type = s->connMan->get_port_type(output_port); + ConnectionType port_type = s->connMan.get_port_type(output_port); int max_vc_size = 0; if (port_type == CONN_GLOBAL) { max_vc_size = s->params->global_vc_size; + cur_chunk->msg.my_g_hop++; + cur_chunk->msg.my_hops_cur_group = 0; } else if (port_type == CONN_LOCAL) { max_vc_size = s->params->local_vc_size; + cur_chunk->msg.my_l_hop++; + cur_chunk->msg.my_hops_cur_group++; } else { assert(port_type == CONN_TERMINAL); @@ -4393,6 +4935,7 @@ static void router_packet_receive(router_state *s, tw_bf *bf, terminal_plus_mess ts = codes_local_latency(lp); tw_event *e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_PLUS_ROUTER, (void **) &m, NULL); + m->rail_id = msg->rail_id; m->type = R_SEND; m->magic = router_magic_num; m->vc_index = output_port; @@ -4638,6 +5181,8 @@ static void router_packet_send(router_state *s, tw_bf *bf, terminal_plus_message s->link_traffic_ross_sample[output_port] += s->params->chunk_size; } + m->rail_id = msg->rail_id; + /* Determine the event type. If the packet has arrived at the final * destination router then it should arrive at the destination terminal * next.*/ @@ -4675,6 +5220,7 @@ static void router_packet_send(router_state *s, tw_bf *bf, terminal_plus_message ts += g_tw_lookahead + tw_rand_unif(lp->rng); e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_PLUS_ROUTER, (void **) &m_new, NULL); m_new->type = R_SEND; + m_new->rail_id = msg->rail_id; m_new->magic = router_magic_num; m_new->vc_index = output_port; tw_event_send(e); @@ -4754,6 +5300,7 @@ static void router_buf_update(router_state *s, tw_bf *bf, terminal_plus_message tw_stime ts = codes_local_latency(lp); tw_event *e = model_net_method_event_new(lp->gid, ts, lp, DRAGONFLY_PLUS_ROUTER, (void **) &m, NULL); m->type = R_SEND; + m->rail_id = msg->rail_id; m->vc_index = indx; m->magic = router_magic_num; s->in_send_loop[indx] = 1; @@ -4930,14 +5477,156 @@ static void router_plus_register(tw_lptype *base_type) lp_type_register(LP_CONFIG_NM_ROUT, base_type); } -/* Routing Functions */ +/* Routing Functions -------------------------------------------- */ + +//This is the old DFP routing before it was split up into its modular version with a switch statement. Keeping it here for a little bit just for easy reference. Should be removed eventually. +// static Connection do_dfp_routing(router_state *s, +// tw_bf *bf, +// terminal_plus_message *msg, +// tw_lp *lp, +// int fdest_router_id) +// { + +// int my_router_id = s->router_id; +// int my_group_id = s->router_id / s->params->num_routers; +// int fdest_group_id = fdest_router_id / s->params->num_routers; +// int origin_group_id = msg->origin_router_id / s->params->num_routers; +// bool in_intermediate_group = (my_group_id != origin_group_id) && (my_group_id != fdest_group_id); + +// Connection nextStopConn; //the Connection that we will forward the packet to + +// //----------- DESTINATION LOCAL GROUP ROUTING -------------- +// if (my_router_id == fdest_router_id) { +// vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfp_dest_terminal_id, CONN_TERMINAL); +// if (poss_next_stops.size() < 1) +// tw_error(TW_LOC, "Destination Router: No Connection to destination terminal\n"); + +// //Not exactly sure why I did this //TODO Address +// // if (poss_next_stops.size() > 1) +// // { +// // vector< Connection > conns_on_rail; +// // for(int i = 0; i < poss_next_stops.size(); i++) +// // { +// // if(poss_next_stops[i].rail_or_planar_id == msg->rail_id) +// // conns_on_rail.push_back(poss_next_stops[i]); +// // } +// // if(conns_on_rail.size() < 1) +// // tw_error(TW_LOC, "Destination Router %d: No Connection to destination terminal %d on specified rail %d\n",s->router_id, msg->dfdally_dest_terminal_id, msg->rail_id); + +// // Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, conns_on_rail); +// // return best_min_conn; +// // } +// // else +// // return poss_next_stops[0]; + +// Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); +// return best_min_conn; +// } +// else if (my_group_id == fdest_group_id) { //then we just route minimally +// vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); +// if (poss_next_stops.size() < 1) +// tw_error(TW_LOC, "DEAD END WHEN ROUTING LOCALLY - My Router ID: %d FDest Router ID: %d (origin router ID: %d)\n", my_router_id, fdest_router_id, msg->origin_router_id); + +// Connection best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); +// return best_min_conn; +// } +// //------------ END DESTINATION LOCAL GROUP ROUTING --------- +// // from here we can assume that we are not in the destination group + +// if(msg->last_hop == TERMINAL) //This is used by dfdally_nonminimal_routing and dfdally_prog_adaptive_routing +// { +// if (msg->intm_grp_id == -1) +// dfp_select_intermediate_group(s, bf, msg, lp, fdest_router_id); +// } + + +// if (isRoutingAdaptive(routing)) { +// if (routing == PROG_ADAPTIVE) +// nextStopConn = dfp_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); +// else if (routing == FULLY_PROG_ADAPTIVE){ +// nextStopConn = dfp_fully_prog_adaptive_routing(s, bf, msg, lp, fdest_router_id); +// } +// return nextStopConn; +// } + +// else if (isRoutingMinimal(routing)) { +// vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); +// if (poss_next_stops.size() < 1) +// tw_error(TW_LOC, "%d group %d: MINIMAL DEAD END to %d in group %d - (s%d -> d%d)\n", s->router_id, s->group_id, fdest_router_id, fdest_router_id / s->params->num_routers, msg->origin_router_id, fdest_router_id); + +// // int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() -1 ); +// // return poss_next_stops[rand_sel]; + +// ConnectionType conn_type = poss_next_stops[0].conn_type; +// Connection best_min_conn; +// if (conn_type == CONN_GLOBAL) { +// msg->num_rngs++; +// int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() -1); +// return poss_next_stops[rand_sel]; +// } +// else +// best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //gets absolute best +// return best_min_conn; +// } + +// else { //routing algorithm is specified in routing +// bool route_to_fdest = false; +// if (routing == NON_MINIMAL_LEAF) { +// if (msg->dfp_upward_channel_flag == 1) //we only route to minimal if this flag is true, otherwise we keep routing nonminimally +// route_to_fdest = true; + +// else if (s->dfp_router_type == LEAF) { +// if (in_intermediate_group) { //then we are the intermediate router +// msg->dfp_upward_channel_flag = 1; +// route_to_fdest = true; +// } +// } +// } +// else if (routing == NON_MINIMAL_SPINE) { +// tw_error(TW_LOC, "nonminimal spine routing not yet supported"); +// } + +// vector< Connection > poss_min_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); +// vector< Connection > poss_intm_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + + +// vector< Connection > poss_next_stops; +// if (route_to_fdest) { +// poss_next_stops = poss_min_next_stops; +// if (poss_next_stops.size() < 1) +// tw_error(TW_LOC, "Dead end when finding stops to fdest router"); +// } +// else { //then we need to be going toward the intermediate router +// msg->path_type = NON_MINIMAL; +// poss_next_stops = poss_intm_next_stops; +// if (poss_next_stops.size() < 1) +// tw_error(TW_LOC, "Dead end when finding stops to intermediate router"); +// } + +// ConnectionType conn_type = poss_next_stops[0].conn_type; //should all be the same + +// Connection best_conn; +// if (conn_type == CONN_GLOBAL) +// best_conn = get_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //pick 2 randomly and pick best from those +// else +// best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //pick absolute best from poss_next_stops + +// if (best_conn.port == -1) +// tw_error(TW_LOC, "Get best Connection returned a bad Connection"); + +// return best_conn; +// } + +// tw_error(TW_LOC, "do_dfp_routing(): No route chosen!\n"); +// } + static int get_min_hops_to_dest_from_conn(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, Connection conn) { int my_type = s->dfp_router_type; int next_hops_type = dragonfly_plus_get_router_type(conn.dest_gid, s->params); int dfp_dest_terminal_id = msg->dfp_dest_terminal_id; - int fdest_router_id = dragonfly_plus_get_assigned_router_id(dfp_dest_terminal_id, s->params); + int fdest_router_id = dragonfly_plus_get_assigned_router_id(s->params, dfp_dest_terminal_id, msg->rail_id); int fdest_group_id = fdest_router_id / s->params->num_routers; if (msg->dfp_upward_channel_flag) @@ -4958,7 +5647,7 @@ static int get_min_hops_to_dest_from_conn(router_state *s, tw_bf *bf, terminal_p } else { //next is not in final destination group if (next_hops_type == SPINE) { - vector< Connection > cons_to_dest_group = connManagerList[conn.dest_gid].get_connections_to_group(fdest_group_id); + vector< Connection > cons_to_dest_group = netMan.get_connection_manager_for_router(conn.dest_gid).get_connections_to_group(fdest_group_id); if (cons_to_dest_group.size() == 0) return 5; //Next Spine -> Leaf -> Spine -> Spine -> Leaf -> dest_term else @@ -5026,13 +5715,15 @@ static vector< Connection > get_router_with_global_links(router_state *s, tw_bf set poss_router_id_set_to_group; int my_group_id = s->router_id / s->params->num_routers; - for(int desg=0; desg< s->params->num_groups; desg++) { - for(int i = 0; i < connectionList[my_group_id][desg].size(); i++) + for(int desg=0; desg< s->params->total_groups; desg++) { + vector global_connected_gids = s->connMan.get_router_gids_with_global_to_group(desg); + + for(int i = 0; i < global_connected_gids.size(); i++) { - int poss_router_id = connectionList[my_group_id][desg][i]; + int poss_router_id = global_connected_gids[i]; // printf("%d\n",poss_router_id); if (poss_router_id_set_to_group.count(poss_router_id) == 0) { //if we haven't added the connections from poss_router_id yet - vector< Connection > conns = s->connMan->get_connections_to_gid(poss_router_id, CONN_LOCAL); + vector< Connection > conns = s->connMan.get_connections_to_gid(poss_router_id, CONN_LOCAL); poss_router_id_set_to_group.insert(poss_router_id); spine_with_global_link.insert(spine_with_global_link.end(), conns.begin(), conns.end()); } @@ -5041,60 +5732,108 @@ static vector< Connection > get_router_with_global_links(router_state *s, tw_bf return spine_with_global_link; } -//Returns a vector of connections that are legal dragonfly plus routes that specifically would not allow for a minimal connection to the specific router specified in get_possible_stops_to_specific_router() -//Be very wary of using this method, results may not make sense if possible_minimal_stops is not a vector of minimal next stops to fdest_rotuer_id -//Nonminimal specifically refers to any move that does not move directly toward the destination router -static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, vector< Connection > possible_minimal_stops, int fdest_router_id) +static void dfp_select_intermediate_group(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + // Has an intermediate group been chosen yet? (Should happen at first router) + if (msg->intm_grp_id == -1) { // Intermediate group hasn't been chosen yet, choose one randomly and route toward it + assert(s->router_id == msg->origin_router_id); + msg->num_rngs++; + int rand_group_id; + if (NONMIN_INCLUDE_SOURCE_DEST) //then any group is a valid intermediate group + rand_group_id = tw_rand_integer(lp->rng, s->params->num_groups*s->plane_id, (s->params->num_groups*(s->plane_id+1))-1); + else { //then we don't consider source or dest groups as valid intermediate groups + vector group_list; + for (int i = s->params->num_groups*s->plane_id; i < s->params->num_groups*(s->plane_id+1); i++) + { + if ((i != origin_group_id) && (i != fdest_group_id)) { + group_list.push_back(i); + } + } + int rand_sel = tw_rand_integer(lp->rng, 0, group_list.size()-1); + rand_group_id = group_list[rand_sel]; + } + msg->intm_grp_id = rand_group_id; + } + else { //the only time that it is re-set is when a router didn't have a direct Connection to the intermediate group but had no other options + // so we need to pick an intm group that the current router DOES have a Connection to. + assert(s->router_id != msg->origin_router_id); + + set< int > valid_intm_groups; + vector< Connection > global_conns = s->connMan.get_connections_by_type(CONN_GLOBAL); + for (vector::iterator it = global_conns.begin(); it != global_conns.end(); it ++) { + Connection conn = *it; + if (NONMIN_INCLUDE_SOURCE_DEST) //then any group I connect to is valid + { + valid_intm_groups.insert(conn.dest_group_id); + } + else + { + if ((conn.dest_group_id != fdest_group_id) && (conn.dest_group_id != origin_group_id)) + valid_intm_groups.insert(conn.dest_group_id); + } + } + + int rand_sel = tw_rand_integer(lp->rng, 0, valid_intm_groups.size()-1); + msg->num_rngs++; + set< int >::iterator it = valid_intm_groups.begin(); + advance(it, rand_sel); //you can't just use [] to access a set + msg->intm_grp_id = *it; + } +} + +//Note this has been updated to no longer be the converse of minimal stops. It now includes any next stops that can get to the intermediate group. This is now in line more with the 1D Dragonfly model. +//previously nonminimal stops being the converse of minimal was the norm as recommended but it seems to not load balance appropriately. +static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) { int my_router_id = s->router_id; int my_group_id = s->router_id / s->params->num_routers; int origin_group_id = msg->origin_router_id / s->params->num_routers; int fdest_group_id = fdest_router_id / s->params->num_routers; bool in_intermediate_group = (my_group_id != origin_group_id) && (my_group_id != fdest_group_id); + int preset_intm_group_id = msg->intm_grp_id; + vector poss_next_nonmin_stops; - vector< Connection > possible_nonminimal_stops; - - if (my_group_id == origin_group_id) { //then we're just sending upward out of the group - if (s->dfp_router_type == LEAF) { //then any connections to spines that are not in possible_minimal_stops should be included - vector< Connection > conns_to_spines = s->connMan->get_connections_by_type(CONN_LOCAL); - possible_nonminimal_stops = set_difference_vectors(conns_to_spines, possible_minimal_stops); //get the complement of possible_minimal_stops - - // for the case that not all spine routers have global link - vector< Connection > spine_with_global_link = get_router_with_global_links(s, bf, msg, lp); - possible_nonminimal_stops = set_common_vectors(possible_nonminimal_stops, spine_with_global_link); + if(my_group_id == origin_group_id) { + if (s->dfp_router_type == LEAF) { + vector conns_to_connecting_routers = s->connMan.get_routed_connections_to_group(preset_intm_group_id, true); + return conns_to_connecting_routers; } - else if (s->dfp_router_type == SPINE) { //then we have to send via global connections that aren't to the dest group - vector< Connection > conns_to_other_groups = s->connMan->get_connections_by_type(CONN_GLOBAL); - possible_nonminimal_stops = set_difference_vectors(conns_to_other_groups, possible_minimal_stops); + else if (s->dfp_router_type == SPINE) { + vector conns_to_group = s->connMan.get_connections_to_group(preset_intm_group_id); + if (conns_to_group.size() < 1) + { + dfp_select_intermediate_group(s, bf, msg, lp, fdest_router_id); + conns_to_group = s->connMan.get_connections_to_group(msg->intm_grp_id); + return conns_to_group; + } + return conns_to_group; } } - else if (in_intermediate_group) { - if (msg->dfp_upward_channel_flag == 1) { //then we return an empty vector as the only legal moves are those that already exist in possible_minimal_stops - assert(possible_nonminimal_stops.size() == 0); - return possible_nonminimal_stops; + if(in_intermediate_group) { + if (msg->dfp_upward_channel_flag == 1) { + return poss_next_nonmin_stops; } else if (s->dfp_router_type == LEAF) { //if we're a leaf in an intermediate group then the routing alg should have flipped the dfp_upward channel already but lets return empty just in case - assert(possible_nonminimal_stops.size() == 0); - return possible_nonminimal_stops; + return poss_next_nonmin_stops; } else if (s->dfp_router_type == SPINE) { //then possible_minimal_stops will be the list of connections assert(msg->dfp_upward_channel_flag == 0); - vector< Connection> conns_to_leaves = s->connMan->get_connections_by_type(CONN_LOCAL); - possible_nonminimal_stops = set_difference_vectors(conns_to_leaves, possible_minimal_stops); //get the complement of possible_minimal_stops + vector< Connection> conns_to_leaves = s->connMan.get_connections_by_type(CONN_LOCAL); + return conns_to_leaves; } - else { - tw_error(TW_LOC, "Impossible Error - Something's majorly wrong if this is tripped"); - } - } + else if (my_group_id == fdest_group_id) { if (s->params->dest_spine_consider_nonmin == true || s->params->dest_spine_consider_global_nonmin == true) { if (s->dfp_router_type == SPINE) { vector< Connection > poss_next_conns; if (s->params->dest_spine_consider_nonmin == true) { - vector< Connection > conns_to_leaves = s->connMan->get_connections_by_type(CONN_LOCAL); + vector< Connection > conns_to_leaves = s->connMan.get_connections_by_type(CONN_LOCAL); for (int i = 0; i < conns_to_leaves.size(); i++) { if (conns_to_leaves[i].dest_gid != fdest_router_id) @@ -5102,7 +5841,7 @@ static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *b } } if (s->params->dest_spine_consider_global_nonmin == true) { - vector< Connection > conns_to_spines = s->connMan->get_connections_by_type(CONN_GLOBAL); + vector< Connection > conns_to_spines = s->connMan.get_connections_by_type(CONN_GLOBAL); for (int i = 0; i < conns_to_spines.size(); i++) { if (conns_to_spines[i].dest_group_id != fdest_group_id && conns_to_spines[i].dest_group_id != origin_group_id) { @@ -5115,23 +5854,105 @@ static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *b } else { assert(s->dfp_router_type == LEAF); - assert(possible_nonminimal_stops.size() == 0); //empty because a leaf in the destination group has no legal nonminimal moves - return possible_nonminimal_stops; + //empty because a leaf in the destination group has no legal nonminimal moves + return poss_next_nonmin_stops; } - - } } - else { - tw_error(TW_LOC, "Invalid group classification\n"); - } - - // assert(possible_nonminimal_stops.size() > 0); - return possible_nonminimal_stops; + return poss_next_nonmin_stops; } +// //Returns a vector of connections that are legal dragonfly plus routes that specifically would not allow for a minimal Connection to the specific router specified in get_possible_stops_to_specific_router() +// //Be very wary of using this method, results may not make sense if possible_minimal_stops is not a vector of minimal next stops to fdest_rotuer_id +// //Nonminimal specifically refers to any move that does not move directly toward the destination router +// static vector< Connection > get_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, vector< Connection > possible_minimal_stops, int fdest_router_id) +// { +// int my_router_id = s->router_id; +// int my_group_id = s->router_id / s->params->num_routers; +// int origin_group_id = msg->origin_router_id / s->params->num_routers; +// int fdest_group_id = fdest_router_id / s->params->num_routers; +// bool in_intermediate_group = (my_group_id != origin_group_id) && (my_group_id != fdest_group_id); + + +// vector< Connection > possible_nonminimal_stops; + +// if (my_group_id == origin_group_id) { //then we're just sending upward out of the group +// if (s->dfp_router_type == LEAF) { //then any connections to spines that are not in possible_minimal_stops should be included +// vector< Connection > conns_to_spines = s->connMan.get_connections_by_type(CONN_LOCAL); +// possible_nonminimal_stops = set_difference_vectors(conns_to_spines, possible_minimal_stops); //get the complement of possible_minimal_stops + +// // for the case that not all spine routers have global link +// vector< Connection > spine_with_global_link = get_router_with_global_links(s, bf, msg, lp); +// possible_nonminimal_stops = set_common_vectors(possible_nonminimal_stops, spine_with_global_link); +// } +// else if (s->dfp_router_type == SPINE) { //then we have to send via global connections that aren't to the dest group +// vector< Connection > conns_to_other_groups = s->connMan.get_connections_by_type(CONN_GLOBAL); +// possible_nonminimal_stops = set_difference_vectors(conns_to_other_groups, possible_minimal_stops); +// } +// } +// else if (in_intermediate_group) { +// if (msg->dfp_upward_channel_flag == 1) { //then we return an empty vector as the only legal moves are those that already exist in possible_minimal_stops +// assert(possible_nonminimal_stops.size() == 0); +// return possible_nonminimal_stops; +// } +// else if (s->dfp_router_type == LEAF) { //if we're a leaf in an intermediate group then the routing alg should have flipped the dfp_upward channel already but lets return empty just in case +// assert(possible_nonminimal_stops.size() == 0); +// return possible_nonminimal_stops; +// } +// else if (s->dfp_router_type == SPINE) { //then possible_minimal_stops will be the list of connections +// assert(msg->dfp_upward_channel_flag == 0); +// vector< Connection> conns_to_leaves = s->connMan.get_connections_by_type(CONN_LOCAL); +// possible_nonminimal_stops = set_difference_vectors(conns_to_leaves, possible_minimal_stops); //get the complement of possible_minimal_stops +// } +// else { +// tw_error(TW_LOC, "Impossible Error - Something's majorly wrong if this is tripped"); +// } + +// } +// else if (my_group_id == fdest_group_id) { +// if (s->params->dest_spine_consider_nonmin == true || s->params->dest_spine_consider_global_nonmin == true) { +// if (s->dfp_router_type == SPINE) { +// vector< Connection > poss_next_conns; + +// if (s->params->dest_spine_consider_nonmin == true) { +// vector< Connection > conns_to_leaves = s->connMan.get_connections_by_type(CONN_LOCAL); +// for (int i = 0; i < conns_to_leaves.size(); i++) +// { +// if (conns_to_leaves[i].dest_gid != fdest_router_id) +// poss_next_conns.push_back(conns_to_leaves[i]); +// } +// } +// if (s->params->dest_spine_consider_global_nonmin == true) { +// vector< Connection > conns_to_spines = s->connMan.get_connections_by_type(CONN_GLOBAL); +// for (int i = 0; i < conns_to_spines.size(); i++) +// { +// if (conns_to_spines[i].dest_group_id != fdest_group_id && conns_to_spines[i].dest_group_id != origin_group_id) { +// poss_next_conns.push_back(conns_to_spines[i]); +// } +// } +// } + +// return poss_next_conns; +// } +// else { +// assert(s->dfp_router_type == LEAF); +// assert(possible_nonminimal_stops.size() == 0); //empty because a leaf in the destination group has no legal nonminimal moves +// return possible_nonminimal_stops; +// } + + +// } +// } +// else { +// tw_error(TW_LOC, "Invalid group classification\n"); +// } + +// // assert(possible_nonminimal_stops.size() > 0); +// return possible_nonminimal_stops; +// } + //The term minimal in this case refers to "Moving toward destination router". If a packet is at an intermediate spine and that spine doesn't -//have a direct connection to the destinatino group, then there wouldn't be any "legal minimal stops". The packet would have to continue to +//have a direct Connection to the destinatino group, then there wouldn't be any "legal minimal stops". The packet would have to continue to //some leaf in the group first. THIS DOES NOT INCLUDE REROUTING. The only time an intermediate leaf can send to an intermediate spine is if //dfp_upward_channel_flag is 0. static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) @@ -5143,28 +5964,17 @@ static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, if (my_group_id != fdest_group_id) { //then we're in the source or the intermediate group. if (s->dfp_router_type == LEAF) { - vector< Connection> possible_next_conns_to_group; - set poss_router_id_set_to_group; - for(int i = 0; i < connectionList[my_group_id][fdest_group_id].size(); i++) - { - int poss_router_id = connectionList[my_group_id][fdest_group_id][i]; - // printf("%d\n",poss_router_id); - if (poss_router_id_set_to_group.count(poss_router_id) == 0) { //if we haven't added the connections from poss_router_id yet - vector< Connection > conns = s->connMan->get_connections_to_gid(poss_router_id, CONN_LOCAL); - poss_router_id_set_to_group.insert(poss_router_id); - possible_next_conns_to_group.insert(possible_next_conns_to_group.end(), conns.begin(), conns.end()); - } - } - return possible_next_conns_to_group; + vector poss_conns_to_next_group = s->connMan.get_routed_connections_to_group(fdest_group_id, true); + return poss_conns_to_next_group; } else if (s->dfp_router_type == SPINE) { - return s->connMan->get_connections_to_group(fdest_group_id); + return s->connMan.get_connections_to_group(fdest_group_id); } } else { assert(my_group_id == fdest_group_id); if (s->dfp_router_type == SPINE) { - vector< Connection > possible_next_conns = s->connMan->get_connections_to_gid(fdest_router_id, CONN_LOCAL); + vector< Connection > possible_next_conns = s->connMan.get_connections_to_gid(fdest_router_id, CONN_LOCAL); return possible_next_conns; } else { @@ -5172,7 +5982,19 @@ static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, if (my_router_id != fdest_router_id) { //then we're also the source group and we need to send to any spine in our group assert(my_group_id == origin_group_id); - return s->connMan->get_connections_by_type(CONN_LOCAL); + if(netMan.is_link_failures_enabled()) { + vector conns = s->connMan.get_connections_by_type(CONN_LOCAL); + vector good_conns; + for(int i = 0; i < conns.size(); i++) + { + int next_src_gid = conns[i].dest_gid; + if(netMan.get_connection_manager_for_router(next_src_gid).is_any_connection_to(fdest_router_id)) + good_conns.push_back(conns[i]); + } + return good_conns; + } + else + return s->connMan.get_connections_by_type(CONN_LOCAL); } else { //then we're the dest router assert(my_router_id == fdest_router_id); @@ -5185,8 +6007,77 @@ static vector< Connection > get_legal_minimal_stops(router_state *s, tw_bf *bf, return empty; } +//TODO make whether there is random or not a configurable setting. +static Connection dfp_minimal_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + vector< Connection > poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "%d group %d: MINIMAL DEAD END to %d in group %d - (s%d -> d%d)\n", s->router_id, s->group_id, fdest_router_id, fdest_router_id / s->params->num_routers, msg->origin_router_id, fdest_router_id); + + // int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() -1 ); + // return poss_next_stops[rand_sel]; + + ConnectionType conn_type = poss_next_stops[0].conn_type; + Connection best_min_conn; + if (conn_type == CONN_GLOBAL) { + msg->num_rngs++; + int rand_sel = tw_rand_integer(lp->rng, 0, poss_next_stops.size() -1); + return poss_next_stops[rand_sel]; + } + else + best_min_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //gets absolute best + return best_min_conn; +} + +static Connection dfp_nonminimal_leaf_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->router_id / s->params->num_routers; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + bool in_intermediate_group = (my_group_id != origin_group_id) && (my_group_id != fdest_group_id); + + bool route_to_fdest = false; + + if (msg->dfp_upward_channel_flag == 1) //we only route to minimal if this flag is true, otherwise we keep routing nonminimally + route_to_fdest = true; + + else if (s->dfp_router_type == LEAF) { + if (in_intermediate_group) { //then we are the intermediate router + msg->dfp_upward_channel_flag = 1; + route_to_fdest = true; + } + } + + vector< Connection > poss_next_stops; + if (route_to_fdest) { + poss_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Dead end when finding stops to fdest router"); + } + else { + msg->path_type = NON_MINIMAL; + poss_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id);; + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Dead end when finding stops to intermediate router"); + } + + ConnectionType conn_type = poss_next_stops[0].conn_type; //should all be the same + + Connection best_conn; + if (conn_type == CONN_GLOBAL) + best_conn = get_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //pick 2 randomly and pick best from those + else + best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); //pick absolute best from poss_next_stops + + if (best_conn.port == -1) + tw_error(TW_LOC, "Get best Connection returned a bad Connection"); + + return best_conn; +} + -static Connection do_dfp_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +static Connection dfp_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) { int my_router_id = s->router_id; int my_group_id = s->router_id / s->params->num_routers; @@ -5201,7 +6092,7 @@ static Connection do_dfp_prog_adaptive_routing(router_state *s, tw_bf *bf, termi Connection nextStopConn; vector< Connection > poss_min_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); - vector< Connection > poss_intm_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, poss_min_next_stops, fdest_router_id); + vector< Connection > poss_intm_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); if ( (poss_min_next_stops.size() == 0) && (poss_intm_next_stops.size() == 0)) tw_error(TW_LOC, "No possible next stops!!!"); @@ -5298,7 +6189,7 @@ static Connection do_dfp_prog_adaptive_routing(router_state *s, tw_bf *bf, termi // Fully Progressive Adaptive Routing (FPAR) // Shpiner, Alexander, et al. "Dragonfly+: Low cost topology for scaling datacenters." HiPINEB 2017 -static Connection do_dfp_FPAR(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +static Connection dfp_fully_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) { int my_router_id = s->router_id; int my_group_id = s->router_id / s->params->num_routers; @@ -5321,7 +6212,7 @@ static Connection do_dfp_FPAR(router_state *s, tw_bf *bf, terminal_plus_message // The check for dest group local routing has already been completed at this point Connection nextStopConn; vector< Connection > poss_min_next_stops = get_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); - vector< Connection > poss_intm_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, poss_min_next_stops, fdest_router_id); + vector< Connection > poss_intm_next_stops = get_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); if ( (poss_min_next_stops.size() == 0) && (poss_intm_next_stops.size() == 0)) tw_error(TW_LOC, "No possible next stops on router %d", my_router_id); @@ -5427,6 +6318,285 @@ static Connection do_dfp_FPAR(router_state *s, tw_bf *bf, terminal_plus_message return nextStopConn; } +//SMART ROUTING: Smart routing is my term for failure aware routing. Leverages the network manager's ability to filter out invalid connections and to return only valid paths between endpoints. +//It's significantly slower in runtime, typically, and is very experimental at this point. Use at own risk. + +static bool is_accessible_by_source_and_fdest(router_state *s, terminal_plus_message *msg, int poss_intm_gid, int fdest_router_id) +{ + try { + bool memo_result = _accessibility_map.at(make_tuple(s->router_id, poss_intm_gid, fdest_router_id)); + return memo_result; + } + catch (exception e) { + + } + + bool is_accessible_by_source = netMan.get_valid_next_hops_conns(s->router_id, poss_intm_gid, (max_hops_per_group-(msg->my_hops_cur_group)), (max_global_hops_minimal-msg->my_g_hop)).size(); + bool is_accessible_by_dest = netMan.get_valid_next_hops_conns(poss_intm_gid, fdest_router_id, 1, 1).size(); //there will have been one local hop and one global hop + bool result = is_accessible_by_source && is_accessible_by_dest; + + _accessibility_map[(make_tuple(s->router_id,poss_intm_gid,fdest_router_id))] = result; + _accessibility_map[(make_tuple(fdest_router_id,poss_intm_gid,s->router_id))] = result; + + return result; +} + +//Note: this isn't currently used as it incurs a severe runtime cost. Intermediate routers are decided by the route itself which forces 2 global hops for nonminimal routes - ensuring that there is an intermediate group. +static void dfp_smart_pick_intermediate_router(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + vector possible_leaf_gids; + + int plane_id = s->plane_id; + int rpp = s->params->num_routers_per_plane; + for(int i = plane_id * rpp; i < (plane_id * rpp)+rpp; i++) + { + router_type type = router_type_map[i]; + if (type == LEAF) + { + int intm_grp_id = i / s->params->num_routers; + if (intm_grp_id != origin_group_id && intm_grp_id != fdest_group_id) + { + if(is_accessible_by_source_and_fdest(s, msg, i, fdest_router_id)) + possible_leaf_gids.push_back(i); + } + } + } + if(possible_leaf_gids.size() == 0) + { + msg->intm_rtr_id = -2; //we CANT reach any leaf routers + return; + } + //pick one at random + msg->num_rngs++; + msg->intm_rtr_id = possible_leaf_gids[tw_rand_integer(lp->rng,0,possible_leaf_gids.size()-1)]; +} + +static set< Connection> get_smart_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id, int max_global_hops_in_path) +{ + set possible_next_dests; + + if(s->group_id == fdest_router_id / s->params->num_routers) + { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), 0); + } + else { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_in_path-msg->my_g_hop)); + } + + return possible_next_dests; +} +//when using this function, you should assume that the self router is NOT the destination. That should be handled elsewhere. +static set< Connection> get_smart_legal_minimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + return get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id, max_global_hops_minimal); +} + +static set get_smart_legal_nonminimal_stops(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + bool in_intermediate_group = (my_group_id != fdest_group_id && my_group_id != origin_group_id); + + set possible_next_dests; + if(s->group_id == fdest_router_id / s->params->num_routers) + { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), 0); + if (possible_next_dests.size() == 0) + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_nonminimal-msg->my_g_hop)); + } + else { + possible_next_dests = netMan.get_valid_next_hops_conns(s->router_id, fdest_router_id, (max_hops_per_group-msg->my_hops_cur_group), (max_global_hops_nonminimal-msg->my_g_hop)); + + //if we havent hit a leaf router yet, we aren't supposed to send along a global link to the dest group if we are in the intermediate group + if (msg->dfp_upward_channel_flag == 0 && s->dfp_router_type == SPINE && in_intermediate_group) + { + set::iterator it = possible_next_dests.begin(); + while(it != possible_next_dests.end()) + { + if (it->conn_type == CONN_GLOBAL) + it = possible_next_dests.erase(it); + else + { + it++; + } + } + } + } + + return possible_next_dests; +} + +//TODO make it so that you can configure whether there is any level of adaptive routing within the minimal routing scheme +static Connection dfp_smart_minimal_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + if(s->router_id == fdest_router_id) + { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfp_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No Connection to destination terminal %d\n", s->router_id, msg->dfp_dest_terminal_id); //shouldn't happen unless math was wrong + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_conn; + } + //do i have a direct Connection to fdest by any chance? + vector direct_conns; + if(my_group_id != fdest_group_id) + direct_conns = s->connMan.get_connections_to_gid(fdest_router_id,CONN_GLOBAL); + else + direct_conns = s->connMan.get_connections_to_gid(fdest_router_id,CONN_LOCAL); + if (direct_conns.size() > 0) { + return get_absolute_best_connection_from_conns(s,bf,msg,lp,direct_conns); + // msg->num_rngs++; + // int offset = tw_rand_integer(lp->rng,0,direct_conns.size()-1); + // return direct_conns[offset]; + } + else + { + set possible_conns = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + + if (possible_conns.size() < 1) + tw_error(TW_LOC, "Smart Routing: Pathfinder messed up\n"); + + + return get_absolute_best_connection_from_conn_set(s,bf,msg,lp,possible_conns); + // msg->num_rngs++; + // int offset = tw_rand_integer(lp->rng,0,possible_conns.size()-1); + // set::iterator it = possible_conns.begin(); + // advance(it, offset); + // return *(it); + } +} + +static Connection dfp_smart_nonminimal_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + + bool in_intermediate_group = (my_group_id != origin_group_id && my_group_id != fdest_group_id); + + if(s->router_id == fdest_router_id) + { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfp_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No Connection to destination terminal %d\n", s->router_id, msg->dfp_dest_terminal_id); //shouldn't happen unless math was wrong + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_conn; + } + + if(in_intermediate_group && s->dfp_router_type == LEAF) + msg->dfp_upward_channel_flag = 1; + + if (in_intermediate_group) + { + msg->path_type = NON_MINIMAL; //become nonminimal the moment that we're not in the source or dest group + } + + set possible_conns = get_smart_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + + if (possible_conns.size() < 1) + tw_error(TW_LOC, "Smart Routing: Pathfinder messed up\n"); + + Connection best_conn = get_absolute_best_connection_from_conn_set(s, bf, msg, lp, possible_conns); + return best_conn; + + + // msg->num_rngs++; + // int offset = tw_rand_integer(lp->rng,0,possible_conns.size()-1); + // set::iterator it = possible_conns.begin(); + // advance(it, offset); + + // printf("Nonmin %d: next dest %d with %d hops\n",s->router_id, it->dest_gid, msg->my_N_hop); + // return *(it); +} + + +static Connection dfp_smart_prog_adaptive_routing(router_state *s, tw_bf *bf, terminal_plus_message *msg, tw_lp *lp, int fdest_router_id) +{ + int my_router_id = s->router_id; + int my_group_id = s->group_id; + int fdest_group_id = fdest_router_id / s->params->num_routers; + int origin_group_id = msg->origin_router_id / s->params->num_routers; + int adaptive_threshold = s->params->adaptive_threshold; + bool in_intermediate_group = (my_group_id != origin_group_id && my_group_id != fdest_group_id); + + if (my_router_id == fdest_router_id) // we're the destination, send to connected terminal + { + if(s->router_id == fdest_router_id) + { + vector< Connection > poss_next_stops = s->connMan.get_connections_to_gid(msg->dfp_dest_terminal_id, CONN_TERMINAL); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Destination Router %d: No Connection to destination terminal %d\n", s->router_id, msg->dfp_dest_terminal_id); //shouldn't happen unless math was wrong + Connection best_conn = get_absolute_best_connection_from_conns(s, bf, msg, lp, poss_next_stops); + return best_conn; + } + } + + if (my_group_id != origin_group_id && my_group_id != fdest_group_id) + { + msg->path_type = NON_MINIMAL; //become nonminimal the moment that we're not in the source or dest group + } + if(in_intermediate_group && s->dfp_router_type == LEAF) + msg->dfp_upward_channel_flag = 1; + + if (msg->dfp_upward_channel_flag == 1) //then we route minimally the rest of the way + { + set poss_min_next_stops = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id, max_global_hops_nonminimal); //there will be a total of max_global_hops_nonminimal in this path + return get_absolute_best_connection_from_conn_set(s, bf, msg, lp, poss_min_next_stops); + } + else + { + if(msg->path_type == NON_MINIMAL) //then we have no choice but to route to the intm router id + { + set poss_next_stops = get_smart_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + if (poss_next_stops.size() < 1) + tw_error(TW_LOC, "Smart Prog Adaptive Routing: intm can't reach intm rtr"); + Connection best_conn = dfp_get_best_from_k_connection_set(s,bf,msg,lp,poss_next_stops,s->params->global_k_picks); + return best_conn; + } + else { + if (my_group_id == origin_group_id) { + set poss_min_next_stops = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + set poss_non_min_next_stops = get_smart_legal_nonminimal_stops(s, bf, msg, lp, fdest_router_id); + + Connection best_min_conn = dfp_get_best_from_k_connection_set(s,bf,msg,lp,poss_min_next_stops,s->params->global_k_picks); + Connection best_nonmin_conn = dfp_get_best_from_k_connection_set(s,bf,msg,lp,poss_non_min_next_stops,s->params->global_k_picks); + + int min_score = dfp_score_connection(s, bf, msg, lp, best_min_conn, C_MIN); + int nonmin_score = dfp_score_connection(s, bf, msg, lp, best_nonmin_conn, C_NONMIN); + + if (min_score <= adaptive_threshold) + return best_min_conn; + else if (min_score <= nonmin_score) + return best_min_conn; + else { + msg->path_type = NON_MINIMAL; + return best_nonmin_conn; + } + } else + { + set poss_min_next_stops = get_smart_legal_minimal_stops(s, bf, msg, lp, fdest_router_id); + Connection best_min_conn = dfp_get_best_from_k_connection_set(s,bf,msg,lp,poss_min_next_stops, s->params->global_k_picks); + return best_min_conn; + } + } + } +} + + extern "C" { /* data structure for dragonfly statistics */ struct model_net_method dragonfly_plus_method = { @@ -5520,7 +6690,7 @@ struct model_net_method dragonfly_plus_router_method = { // // int lid_r1 = r1 % params->num_routers; // // int lid_r2 = r2 % params->num_routers; -// // /* The connection will be there if the router is in the same row or +// // /* The Connection will be there if the router is in the same row or // // * same column */ // // int src_row_r1 = lid_r1 / params->num_router_cols; // // int src_row_r2 = lid_r2 / params->num_router_cols; diff --git a/src/networks/model-net/loggp.c b/src/networks/model-net/loggp.c index 5d5a3f3f..22904287 100644 --- a/src/networks/model-net/loggp.c +++ b/src/networks/model-net/loggp.c @@ -19,8 +19,8 @@ #include "codes/codes.h" #include "codes/net/loggp.h" -#define CATEGORY_NAME_MAX 16 -#define CATEGORY_MAX 12 +// #define CATEGORY_NAME_MAX 16 +// #define CATEGORY_MAX 12 #define LP_CONFIG_NM (model_net_lp_config_names[LOGGP]) #define LP_METHOD_NM (model_net_method_names[LOGGP]) diff --git a/src/networks/model-net/network-managers/dragonfly-network-manager.C b/src/networks/model-net/network-managers/dragonfly-network-manager.C new file mode 100644 index 00000000..34a5e806 --- /dev/null +++ b/src/networks/model-net/network-managers/dragonfly-network-manager.C @@ -0,0 +1,1516 @@ +#include "codes/network-manager/dragonfly-network-manager.h" + +#define ENABLE_SHORT_PATH_CALC 0 +#define MAX_PATH_VAL 999 +#define DEST -999 + +void add_as_if_set_int(int value, vector& vec) +{ + vector::iterator it; + it = std::find(vec.begin(), vec.end(), value); + if (it == vec.end()) //then it's not in the vector yet - else do nothing + vec.push_back(value); +} + +int isNotVisited(int x, vector& path) +{ + int size = path.size(); + for (int i = 0; i < size; i++) + if (path[i] == x) + return 0; + return 1; +} + +DragonflyNetworkManager::DragonflyNetworkManager() +{ + _total_routers = 0; + _num_routers_per_group = 0; + _total_groups = 0; + _num_lc_pr = 0; + _num_gc_pr = 0; + _num_cn_pr = 0; + _is_solidified = false; +} + +DragonflyNetworkManager::DragonflyNetworkManager(int total_routers, int total_terminals, int num_routers_per_group, int num_lc_per_router, int num_gc_per_router, int num_cn_conns_per_router, int num_rails, int num_planes, int max_local_hops, int max_global_hops) +{ + _total_routers = total_routers; + _total_terminals = total_terminals; + _total_groups = total_routers / num_routers_per_group; + _num_rails = num_rails; + _total_planes = num_planes; + _num_routers_per_group = num_routers_per_group; + _num_groups_per_plane = _total_groups / num_planes; + _num_lc_pr = num_lc_per_router; + _num_gc_pr = num_gc_per_router; + _num_cn_pr = num_cn_conns_per_router; + + _max_local_hops_per_group = max_local_hops; + _max_global_hops = max_global_hops; + + _num_router_conns = 0; + _num_router_terminal_conns = 0; + _link_failures_enabled = false; + _num_failed_router_conns = 0; + _num_failed_router_terminal_conns = 0; + + + if (total_routers % num_routers_per_group != 0) + tw_error(TW_LOC, "NetworkManager: total routers \% num routers per group is not evenly divisible, non-uniform groups\n"); + + + for(int i = 0; i < _total_routers; i++) + { + int src_id_global = i; + int src_id_local = i % _num_routers_per_group; + int src_group = i / _num_routers_per_group; + + DragonflyConnectionManager conn_man = DragonflyConnectionManager(src_id_local, src_id_global, src_group, _num_lc_pr, _num_gc_pr, _num_cn_pr, 0, _num_routers_per_group, _num_groups_per_plane, _total_planes, MAN_ROUTER); + _connection_manager_list.push_back(conn_man); + } + + for(int i = 0; i < _total_terminals; i++) + { + int src_id_global = i; + int src_id_local = src_id_global % num_cn_conns_per_router; + int src_group = -1; + + DragonflyConnectionManager conn_man = DragonflyConnectionManager(src_id_local, src_id_global, src_group, 0, 0, 0, num_rails, _num_routers_per_group, _num_groups_per_plane, _total_planes, MAN_TERMINAL); + _terminal_connection_manager_list.push_back(conn_man); + } + + _is_solidified = false; +} + + +void DragonflyNetworkManager::add_link(Link_Info link) +{ + Connection *conn = (Connection*)malloc(sizeof(Connection)); + conn->port = -1; //will be set by the Connection Manager of the router (src_gid) and defined in add_cons_to_connectoin_managers + conn->src_lid = (link.src_gid) % _num_routers_per_group; + conn->src_gid = link.src_gid; + conn->src_group_id = link.src_gid / _num_routers_per_group; + conn->dest_lid = (link.dest_gid) % _num_routers_per_group; + conn->dest_gid = link.dest_gid; + conn->dest_group_id = link.dest_gid / _num_routers_per_group; + conn->conn_type = link.conn_type; + conn->rail_or_planar_id = link.rail_id; + conn->is_failed = false; + + if (link.conn_type != CONN_TERMINAL) + { + _num_router_conns++; + + vector existing_conns_from_src = _router_connections_map[link.src_gid]; + int num_conns = 0; + for(int i = 0; i < existing_conns_from_src.size(); i++) + { + if (existing_conns_from_src[i]->dest_gid == conn->dest_gid) + num_conns++; + } + conn->link_id = num_conns; + + //put the conn into its owning structure + _router_connections_map[link.src_gid].push_back(conn); + + //put into useful maps + _router_to_router_connection_map[make_pair(conn->src_gid,conn->dest_gid)].push_back(conn); + + if (conn->conn_type == CONN_GLOBAL) + { + _global_group_connection_map[make_pair(conn->src_group_id, conn->dest_group_id)].push_back(conn); + _router_to_router_global_conn_map[link.src_gid].push_back(conn); + } + if (conn->conn_type == CONN_LOCAL) + { + _router_to_router_local_conn_map[link.src_gid].push_back(conn); + } + + _router_to_group_connection_map[make_pair(conn->src_gid, conn->dest_group_id)].push_back(conn); + } + else //CONN TERMINAL + { + _num_router_terminal_conns++; + + vector existing_conns_from_src = _router_terminal_connections_map[link.src_gid]; + int num_conns = 0; + for(int i = 0; i < existing_conns_from_src.size(); i++) + { + if (existing_conns_from_src[i]->dest_gid == conn->dest_gid) + num_conns++; + } + conn->link_id = num_conns; + + conn->dest_group_id = conn->src_group_id; + conn->dest_lid = conn->dest_gid % _num_cn_pr; + //put conn into owning structure + _router_terminal_connections_map[link.src_gid].push_back(conn); + + //put into useful maps + _router_to_terminal_connection_map[make_pair(conn->src_gid,conn->dest_gid)].push_back(conn); + _router_ids_with_terminals.insert(conn->src_gid); + + _num_terminal_router_conns++; + //Terminals don't have their own interconnection mapping file that has both links so we need to create a + //new connection for the terminal connection manager too that goes from the terminal to the router. + Connection *term_conn = (Connection*)malloc(sizeof(Connection)); + term_conn->port = conn->rail_or_planar_id; + term_conn->src_lid = conn->dest_lid; + term_conn->src_gid = conn->dest_gid; + term_conn->dest_lid = conn->src_lid; + term_conn->dest_gid = conn->src_gid; + term_conn->src_group_id = -1; + term_conn->dest_group_id = conn->src_group_id; + term_conn->conn_type = CONN_INJECTION; + term_conn->rail_or_planar_id = conn->rail_or_planar_id; + term_conn->is_failed = false; + + _terminal_router_connections_map[term_conn->src_gid].push_back(term_conn); + _terminal_to_router_connection_map[make_pair(term_conn->src_gid, term_conn->dest_gid)].push_back(term_conn); + } +} + + +void DragonflyNetworkManager::calculate_floyd_warshall_shortest_paths() +{ + if(!g_tw_mynode) + printf("\nNetwork Manager: Performing Shortest Path Calculations...\n"); + + _shortest_path_vals = (int**)calloc(_total_routers, sizeof(int*)); + _next = (int**)calloc(_total_routers, sizeof(int*)); + int** costMat = (int**)malloc(_total_routers* sizeof(int*)); + int** dist = (int**)malloc(_total_routers* sizeof(int*)); + for(int i = 0; i < _total_routers; i++) + { + _shortest_path_vals[i] = (int*)calloc(_total_routers, sizeof(int)); + _next[i] = (int*)calloc(_total_routers, sizeof(int)); + costMat[i] = (int*)calloc(_total_routers, sizeof(int)); + dist[i] = (int*)calloc(_total_routers, sizeof(int)); + for(int j = 0; j < _total_routers; j++) + { + _shortest_path_nexts[make_pair(i,j)] = vector(); + } + } + + + //set up cost matrix + // int costMat[_total_routers][_total_routers]; + for(int i = 0; i < _total_routers; i++) + { + for(int j = 0; j <_total_routers; j++) + { + int plane_id = j / (_total_routers / _total_planes); + int src_gid = i; + int dest_gid = j; + int is_adj = adjacency_matrix_nofail[plane_id][i][j]; + // printf("%d ",adjacency_matrix_nofail[i][j]); + if (is_adj) + costMat[i][j] = 1; + else if (i == j) + costMat[i][j] = 0; + else + costMat[i][j] = MAX_PATH_VAL; + } + // printf("\n"); + } + + // int dist[_total_routers][_total_routers]; + for(int i = 0; i < _total_routers; i++) + { + for(int j = 0; j < _total_routers; j++) + { + dist[i][j] = costMat[i][j]; + if(dist[i][j] == 1) + { + _next[i][j] = j; + _shortest_path_nexts[make_pair(i,j)].push_back(j); + } + } + } + for(int i = 0; i < _total_routers; i++) + { + dist[i][i] = 0; + _next[i][i] = i; + _shortest_path_nexts[make_pair(i,i)].push_back(i); + } + + int rpp = _total_routers / _total_planes; + for(int p = 0; p < _total_planes; p++) //we don't need to attempt to calculate distances between planes + { + for(int k = p*rpp; k < rpp + p*rpp; k++) + { + for(int i = p*rpp; i < rpp + p*rpp; i++) + { + for(int j = p*rpp; j < rpp + p*rpp; j++) + { + if(dist[i][j] > dist[i][k] + dist[k][j]) + { + dist[i][j] = dist[i][k] + dist[k][j]; + _shortest_path_nexts[make_pair(i,j)].clear(); + _shortest_path_nexts[make_pair(i,j)].push_back(_next[i][k]); + _next[i][j] = _next[i][k]; + + } + else if (dist[i][k] + dist[k][j] == dist[i][j] && dist[i][j] != MAX_PATH_VAL && k != j && k != i) + { + _shortest_path_nexts[make_pair(i,j)].push_back(k); + } + } + } + } + } + + + for(int i = 0; i <_total_routers; i++) + { + for(int j = 0; j < _total_routers; j++) + { + + _shortest_path_vals[i][j] = dist[i][j]; + // printf("%d ",_shortest_path_vals[i][j]); + } + // printf("\n"); + } + + for(int i = 0; i < _total_routers; i++) + { + free(dist[i]); + free(costMat[i]); + } + free(dist); + free(costMat); +} + +int DragonflyNetworkManager::get_shortest_dist_between_routers(int src_gid, int dest_gid) +{ + return _shortest_path_vals[src_gid][dest_gid]; +} + +vector DragonflyNetworkManager::get_shortest_nexts(int src_gid, int dest_gid) +{ + if(_shortest_path_nexts[make_pair(src_gid,dest_gid)][0] == dest_gid) + { + vector dest; + dest.push_back(dest_gid); + return dest; + } + else { + return _shortest_path_nexts[make_pair(src_gid,dest_gid)]; + } +} + +void DragonflyNetworkManager::enable_link_failures() +{ + _link_failures_enabled = true; +} + +bool DragonflyNetworkManager::is_link_failures_enabled() +{ + return _link_failures_enabled; +} + +DragonflyConnectionManager& DragonflyNetworkManager::get_connection_manager_for_router(int router_gid) +{ + return _connection_manager_list[router_gid]; +} + +DragonflyConnectionManager& DragonflyNetworkManager::get_connection_manager_for_terminal(int terminal_gid) +{ + return _terminal_connection_manager_list[terminal_gid]; +} + +int DragonflyNetworkManager::get_max_local_hops() +{ + return _max_local_hops_per_group; +} + +int DragonflyNetworkManager::get_max_global_hops() +{ + return _max_global_hops; +} + +void DragonflyNetworkManager::add_link_failure_info(Link_Info link) +{ + if(_link_failures_enabled == false) + tw_error(TW_LOC,"Network Manager: attempting to add link failure info but link failure has not been enabled via NetworkManager.allow_link_failures()\n"); + + if (link.conn_type != CONN_TERMINAL) + { + _router_link_failure_lists[link.src_gid].push_back(link); + _num_failed_router_conns++; + } + else + { + _router_terminal_link_failure_lists[link.src_gid].push_back(link); + _num_failed_router_terminal_conns++; + } +} + +int DragonflyNetworkManager::get_failed_count_from_vector(vector conns) +{ + int count = 0; + vector::iterator it = conns.begin(); + for(; it != conns.end(); it++) + { + if ((*it)->is_failed) + count++; + } + return count; +} + +void DragonflyNetworkManager::fail_connection(Link_Info link) +{ + if(_link_failures_enabled == false) + tw_error(TW_LOC,"Network Manager: attempting to fail link but link failure has not been enabled via NetworkManager.allow_link_failures()\n"); + + if (link.conn_type != CONN_TERMINAL) + { + vector conns_to_gid = _router_to_router_connection_map[make_pair(link.src_gid,link.dest_gid)]; + int num_failed_already = get_failed_count_from_vector(conns_to_gid); + if (num_failed_already == conns_to_gid.size()) + tw_error(TW_LOC, "Attempting to fail more links from router GID %d to router GID %d than exist; Link Type %d; Already Failed %d\n", link.src_gid, link.dest_gid, link.conn_type, num_failed_already); + + vector:: iterator it = _router_to_router_connection_map[make_pair(link.src_gid,link.dest_gid)].begin(); + for(; it != _router_to_router_connection_map[make_pair(link.src_gid,link.dest_gid)].end(); it++) + { + if(!(*it)->is_failed) + { + (*it)->is_failed = 1; + break; + } + } + } + else + { + vector conns_to_term_gid = _router_to_terminal_connection_map[make_pair(link.src_gid,link.dest_gid)]; + int num_failed_already = get_failed_count_from_vector(conns_to_term_gid); + if (num_failed_already == conns_to_term_gid.size()) + tw_error(TW_LOC, "Attempting to fail more links from router GID %d to Terminal GID %d than exist. Already Failed %d\n", link.src_gid, link.dest_gid, num_failed_already); + + int failed_rail = 0; + vector:: iterator it = _router_to_terminal_connection_map[make_pair(link.src_gid,link.dest_gid)].begin(); + for(; it != _router_to_terminal_connection_map[make_pair(link.src_gid,link.dest_gid)].end(); it++) + { + if(!(*it)->is_failed) + { + (*it)->is_failed = 1; + failed_rail = (*it)->rail_or_planar_id; + break; + } + } + + //we also need to fail the corresponding injection link + int router_id = link.src_gid; + int term_id = link.dest_gid; + + it =_terminal_to_router_connection_map[make_pair(term_id,router_id)].begin(); + for(; it != _terminal_to_router_connection_map[make_pair(term_id,router_id)].end(); it++) + { + if((*it)->rail_or_planar_id == failed_rail) + { + (*it)->is_failed = 1; + break; + } + } + } +} + + +set DragonflyNetworkManager::get_valid_next_hops_conns(int src_gid, int dest_gid, int max_local, int exact_global) +{ + setvalid_nexts; + if((src_gid / (_total_routers/_total_planes)) != (dest_gid / (_total_routers/_total_planes))) + { + return valid_nexts; //different planes have no valid path between them + } + + if(src_gid == dest_gid && exact_global == 0) { + Connection dest_conn; + dest_conn.dest_gid == DEST; + valid_nexts.insert(dest_conn); + return valid_nexts; + } + if(max_local >= 0 && exact_global >=0) + { + try { + valid_nexts = _valid_next_conn_map.at(make_tuple(src_gid,dest_gid,max_local,exact_global)); + return valid_nexts; + } catch (exception e) { + // printf("<%d,%d,%d,%d>nonmemo'd\n",src_gid, dest_gid, max_local, exact_global); + + vector local_conns_from_src = _router_to_router_local_conn_map[src_gid]; + vector global_conns_from_src = _router_to_router_global_conn_map[src_gid]; + + if (max_local > 0) + { + for(int i = 0; i < local_conns_from_src.size(); i++) + { + if (local_conns_from_src[i]->is_failed == false) + { + set ret_valid; + ret_valid = get_valid_next_hops_conns(local_conns_from_src[i]->dest_gid, dest_gid, max_local-1, exact_global); + if (ret_valid.size() > 0) + { + valid_nexts.insert(*local_conns_from_src[i]); + } + } + } + } + if (exact_global > 0) + { + for(int i = 0; i < global_conns_from_src.size(); i++) + { + if (global_conns_from_src[i]->is_failed == false) + { + set ret_valid; + ret_valid = get_valid_next_hops_conns(global_conns_from_src[i]->dest_gid, dest_gid, _max_local_hops_per_group, exact_global-1); + if (ret_valid.size() > 0) + { + valid_nexts.insert(*global_conns_from_src[i]); + } + } + } + } + _valid_next_conn_map[make_tuple(src_gid,dest_gid,max_local,exact_global)].insert(valid_nexts.begin(),valid_nexts.end()); + } + } + return valid_nexts; +} + +void DragonflyNetworkManager::add_conns_to_connection_managers() +{ + for(int i = 0; i < _total_routers; i++) + { + vector conn_vec = _router_connections_map[i]; + for(int j = 0; j < conn_vec.size(); j++) + { + int port_no = _connection_manager_list[i].add_connection(*conn_vec[j]); + conn_vec[j]->port = port_no; + } + } + + for(int i = 0; i < _total_routers; i++) + { + vector conn_vec = _router_terminal_connections_map[i]; + for(int j = 0; j < conn_vec.size(); j++) + { + int port_no = _connection_manager_list[i].add_connection(*conn_vec[j]); + conn_vec[j]->port = port_no; + } + } + + for(int i = 0; i < _total_terminals; i++) + { + vector conn_vec = _terminal_router_connections_map[i]; + for(int j = 0; j < conn_vec.size(); j++) + { + _terminal_connection_manager_list[i].add_connection(*conn_vec[j]); + } + } + + for(int i = 0; i < _total_routers; i++) + { + int src_grp_id = i / _num_routers_per_group; + + map< int, vector< Connection > > map_for_this_router_to_groups; + for(int j = 0; j < _total_groups; j++) + { + int dest_grp_id = j; + pair group_pair = make_pair(src_grp_id, dest_grp_id); + vector derefd_vec; + for(vector::iterator it = _global_group_connection_map[group_pair].begin(); it!= _global_group_connection_map[group_pair].end(); it++) + { + derefd_vec.push_back(*(*it)); + } + map_for_this_router_to_groups[dest_grp_id] = derefd_vec; + } + _connection_manager_list[i].set_routed_connections_to_groups(map_for_this_router_to_groups); + _connection_manager_list[i].add_group_group_connection_information(_global_group_connection_map); + + } +} + + +void DragonflyNetworkManager::solidify_network() +{ + + adjacency_matrix = (int***)calloc(_total_planes, sizeof(int**)); + adjacency_matrix_nofail = (int***)calloc(_total_planes, sizeof(int**)); + + for(int i = 0; i < _total_planes; i++) + { + adjacency_matrix[i] = (int**)calloc(_total_routers, sizeof(int*)); + adjacency_matrix_nofail[i] = (int**)calloc(_total_routers, sizeof(int*)); + for(int j = 0; j < _total_routers; j++) + { + adjacency_matrix[i][j] = (int*)calloc(_total_routers,sizeof(int)); + adjacency_matrix_nofail[i][j] = (int*)calloc(_total_routers,sizeof(int)); + } + } + + + for(int i = 0; i < _total_routers; i++) + { + int src_gid = i; + vector conns_from_src = _router_connections_map[src_gid]; + vector::iterator it = conns_from_src.begin(); + for(; it != conns_from_src.end(); it++) + { + int plane_id = (*it)->rail_or_planar_id; + int dest_gid = (*it)->dest_gid; + adjacency_matrix[plane_id][src_gid][dest_gid] = 1; //bidirectional will be handled later in the loop + } + } + + map >::iterator it; + //fail the router router connections + for(it = _router_link_failure_lists.begin(); it != _router_link_failure_lists.end(); it++) + { + //iterate over vector of link info + for(int i = 0; i < it->second.size(); i++) + { + Link_Info link = it->second[i]; + fail_connection(link); + } + } + + //fail the router terminal connections + for(it = _router_terminal_link_failure_lists.begin(); it != _router_terminal_link_failure_lists.end(); it++) + { + //iterate over vector of link info + for(int i = 0; i < it->second.size(); i++) + { + Link_Info link = it->second[i]; + fail_connection(link); + } + } + + for(int i = 0; i < _total_routers; i++) + { + int src_gid = i; + vector conns_from_src = _router_connections_map[src_gid]; + vector::iterator it = conns_from_src.begin(); + for(; it != conns_from_src.end(); it++) + { + int plane_id = (*it)->rail_or_planar_id; + int dest_gid = (*it)->dest_gid; + if((*it)->is_failed == false) + adjacency_matrix_nofail[plane_id][src_gid][dest_gid] = 1; //bidirectional will be handled later in the loop + } + } + + if(ENABLE_SHORT_PATH_CALC) + calculate_floyd_warshall_shortest_paths(); + + //add copies of all of the connections to the connection managers + add_conns_to_connection_managers(); + for(vector::iterator it = _connection_manager_list.begin(); it != _connection_manager_list.end(); it++) + { + it->solidify_connections(); //solidify those connection managers + } + for(vector::iterator it = _terminal_connection_manager_list.begin(); it != _terminal_connection_manager_list.end(); it++) + { + it->solidify_connections(); + } + + if(is_link_failures_enabled()) + { + printf("Network Manager: precalculating valid paths\n"); + int rpp = _total_routers / _total_planes; + for(int p = 0; p < _total_planes; p++) + { + for(int i = 0; i < rpp;i++) + { + for(int j = 0; j < rpp;j++) + { + int src_gid = i + (p*rpp); + int dest_gid = j + (p*rpp); + // if (_router_ids_with_terminals.count(src_gid) > 0 && _router_ids_with_terminals.count(dest_gid) > 0) { + // printf("next from %d to %d\n",src_gid,dest_gid); + for(int local_hops = 0; local_hops <= _max_local_hops_per_group; local_hops++) { + set ret_valid = get_valid_next_hops_conns(src_gid,dest_gid,local_hops,_max_global_hops); + _valid_next_conn_map[make_tuple(src_gid,dest_gid,local_hops,_max_global_hops)].insert(ret_valid.begin(), ret_valid.end()); + // printf("Precalc <%d,%d,%d,%d>\n",src_gid,dest_gid,local_hops,_max_global_hops); + } + // } + } + } + } + } + + + _is_solidified = true; //the network is now solidified +} + + +//******************* Connection Manager Implementation ******************************************* +DragonflyConnectionManager::DragonflyConnectionManager() +{ + DragonflyConnectionManager(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MAN_ROUTER); +} + +DragonflyConnectionManager::DragonflyConnectionManager(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, int num_groups) +{ + DragonflyConnectionManager(src_id_local, src_id_global, src_group, max_intra, max_inter, max_term, 0, num_router_per_group, num_groups, 1, MAN_ROUTER); +} + +DragonflyConnectionManager::DragonflyConnectionManager(int src_id_local, int src_id_global, int src_group, int max_intra, int max_inter, int max_term, int max_injection, int num_router_per_group, int num_groups, int num_planes, ManagerType manType) +{ + _manType = manType; + + _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; + _used_injection_ports = 0; + + _failed_intra_ports = 0; + _failed_inter_ports = 0; + _failed_terminal_ports = 0; + _failed_injection_ports = 0; + + _max_intra_ports = max_intra; + _max_inter_ports = max_inter; + _max_terminal_ports = max_term; + _max_injection_ports = max_injection; + + _num_routers_per_group = num_router_per_group; + _num_groups = num_groups; + + is_solidified = false; +} + +int DragonflyConnectionManager::add_connection(int dest_gid, ConnectionType type) +{ + if (is_solidified) + tw_error(TW_LOC,"DragonflyConnectionManager: Attempting to add connections after manager has been solidified!\n"); + + Connection conn; + conn.src_lid = _source_id_local; + conn.src_gid = _source_id_global; + conn.src_group_id = _source_group; + conn.conn_type = type; + conn.dest_lid = dest_gid % _num_routers_per_group; + conn.dest_gid = dest_gid; + conn.dest_group_id = dest_gid / _num_routers_per_group; + conn.is_failed = 0; + + int port = add_connection(conn); + return port; +} + +int DragonflyConnectionManager::add_connection(Connection conn) +{ + if (is_solidified) + tw_error(TW_LOC,"DragonflyConnectionManager: Attempting to add connections after manager has been solidified!\n"); + + switch (conn.conn_type) + { + case CONN_LOCAL: + if (_manType == MAN_TERMINAL) + tw_error(TW_LOC, "Attempting to add local connections to a terminal connection manager\n"); + if (_used_intra_ports < _max_intra_ports){ + conn.port = this->get_used_ports_for(CONN_LOCAL); + intraGroupConnections[conn.dest_lid].push_back(conn); + intraGroupConnectionsGID[conn.dest_gid].push_back(conn); + _used_intra_ports++; + _connected_to_router_gids.insert(conn.dest_gid); + } + else + tw_error(TW_LOC,"Attempting to add too many local connections per router - exceeding configuration value: %d",_max_intra_ports); + break; + case CONN_GLOBAL: + // printf("R%d P%d: Global Add to %d\n", _source_id_global, conn.rail_or_planar_id, conn.dest_gid); + + if (_manType == MAN_TERMINAL) + tw_error(TW_LOC, "Attempting to add global connections to a terminal connection manager\n"); + if(_used_inter_ports < _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++; + _connected_to_router_gids.insert(conn.dest_gid); + } + else + tw_error(TW_LOC,"Attempting to add too many global connections per router - exceeding configuration value: %d",_max_inter_ports); + break; + case CONN_TERMINAL: + if (_manType == MAN_TERMINAL) + tw_error(TW_LOC, "Attempting to add terminal connections to a terminal connection manager\n"); + if(_used_terminal_ports < _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++; + _connected_to_terminal_gids.insert(conn.dest_gid); + } + else + tw_error(TW_LOC,"Attempting to add too many terminal connections per router - exceeding configuration value: %d",_max_terminal_ports); + break; + case CONN_INJECTION: + if(_used_injection_ports < _max_injection_ports){ + injectionConnections[conn.dest_gid].push_back(conn); + _used_injection_ports++; + _connected_to_router_gids.insert(conn.dest_gid); + } + break; + default: + assert(false); + } + + _portMap[conn.port] = conn; + return conn.port; +} + +void DragonflyConnectionManager::add_group_group_connection_information(map, vector > group_group_connections) +{ + map, vector >::iterator map_it = group_group_connections.begin(); + for(; map_it != group_group_connections.end(); map_it++) + { + pair pair_key = map_it->first; + int src_grp = pair_key.first; + int dest_grp = pair_key.second; + + if(map_it->second.size() > 0) + { + add_as_if_set_int(dest_grp, _group_group_connection_map[src_grp]); + add_as_if_set_int(src_grp, _group_group_connection_map[dest_grp]); + } + + vector::iterator vec_it = map_it->second.begin(); + for(; vec_it != map_it->second.end(); vec_it++) + { + if((*vec_it)->is_failed == false) + { + add_as_if_set_int(dest_grp, _group_group_connection_map_nofail[src_grp]); + add_as_if_set_int(src_grp, _group_group_connection_map_nofail[dest_grp]); + break; + } + } + } +} + +void DragonflyConnectionManager::set_routed_connections_to_groups(map > conn_map) +{ + _routed_connections_to_group_map = conn_map; +} + +vector< Connection > DragonflyConnectionManager::get_routed_connections_to_group(int group_id, bool get_next_hop, bool include_failed) +{ + vector< Connection > conns; + vector< Connection >::iterator it; + + if (include_failed == false) + { + for(it = _routed_connections_to_group_map_nofail[group_id].begin(); it != _routed_connections_to_group_map_nofail[group_id].end(); it++) + { + + if (get_next_hop) //then verify that we have a direct connection to the src_lid of this routed conn + { + vector< Connection > local_conns = get_connections_to_gid(it->src_gid, CONN_LOCAL, include_failed); + conns.insert(conns.end(), local_conns.begin(), local_conns.end()); + } + else + { + if(!include_failed) + { + if(it->is_failed == false) + conns.push_back(*it); + } + else + conns.push_back(*it); + } + } + } + else{ + for(it = _routed_connections_to_group_map[group_id].begin(); it != _routed_connections_to_group_map[group_id].end(); it++) + { + + if (get_next_hop) //then verify that we have a direct connection to the src_lid of this routed conn + { + vector< Connection > local_conns = get_connections_to_gid(it->src_gid, CONN_LOCAL, include_failed); + conns.insert(conns.end(), local_conns.begin(), local_conns.end()); + } + else + { + conns.push_back(*it); + } + } + } + + return conns; +} + +vector< Connection > DragonflyConnectionManager::get_routed_connections_to_group(int group_id, bool get_next_hop) +{ + return get_routed_connections_to_group(group_id, get_next_hop, false); +} + +vector< Connection > DragonflyConnectionManager::get_next_hop_routed_connections_to_group(int group_id, bool include_failed) +{ + if (include_failed) + return _next_hop_routed_connections_to_group_map[group_id]; + else + return _next_hop_routed_connections_to_group_map_nofail[group_id]; +} + +vector< Connection > DragonflyConnectionManager::get_next_hop_routed_connections_to_group(int group_id) +{ + return get_next_hop_routed_connections_to_group(group_id, false); +} + +vector< int > DragonflyConnectionManager::get_accessible_group_ids() +{ + return _accessible_group_ids_nofail; +} + +vector< int > DragonflyConnectionManager::get_router_gids_with_global_to_group(int group_id) +{ + return get_router_gids_with_global_to_group(group_id, false); +} + +vector< int > DragonflyConnectionManager::get_router_gids_with_global_to_group(int group_id, bool include_failed) +{ + try { + if (include_failed) + return _routed_router_gids_to_group_map.at(group_id); + else + return _routed_router_gids_to_group_map_nofail.at(group_id); + } catch (exception e) { + return vector(); + } +} + + +vector< int > DragonflyConnectionManager::get_groups_that_connect_to_group(int dest_group, bool include_failed) +{ + try{ + if (include_failed) + return _group_group_connection_map.at(dest_group); + else + return _group_group_connection_map_nofail.at(dest_group); + } catch (exception e) { + return vector(); + } + +} + +vector< int > DragonflyConnectionManager::get_groups_that_connect_to_group(int dest_group) +{ + return get_groups_that_connect_to_group(dest_group, false); +} + +int DragonflyConnectionManager::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 DragonflyConnectionManager::get_ports(int dest_id, ConnectionType type, bool include_failed) +{ + vector< Connection > conns = this->get_connections_to_gid(dest_id, type); + + vector< int > ports_used; + vector< Connection >::iterator it = conns.begin(); + for(; it != conns.end(); it++) { + if (it->is_failed == 0 || include_failed) + ports_used.push_back((*it).port); //add port from connection list to the used ports list + } + return ports_used; +} + +vector DragonflyConnectionManager::get_ports(int dest_id, ConnectionType type) +{ + return get_ports(dest_id, type, false); +} + +Connection DragonflyConnectionManager::get_connection_on_port(int port, bool include_failed) +{ + Connection conn = _portMap[port]; + if (conn.is_failed == 0 || include_failed) + return conn; + else + { + Connection empty_conn; + empty_conn.port = -1; + return empty_conn; + } +} + +Connection DragonflyConnectionManager::get_connection_on_port(int port) +{ + return get_connection_on_port(port, true); +} + +bool DragonflyConnectionManager::is_connected_to_by_type(int dest_id, ConnectionType type) +{ + return is_connected_to_by_type(dest_id, type, false); //by default, don't include failed links +} + +bool DragonflyConnectionManager::is_connected_to_by_type(int dest_id, ConnectionType type, bool include_failed) +{ + if (include_failed) { + if (intraGroupConnectionsGID.find(dest_id) != intraGroupConnectionsGID.end()) + return true; + if (globalConnections.find(dest_id) != globalConnections.end()) + return true; + if (terminalConnections.find(dest_id) != terminalConnections.end()) + return true; + + return false; + } + else { + if (intraGroupConnectionsGID_nofail.find(dest_id) != intraGroupConnectionsGID_nofail.end()) + return true; + if (globalConnections_nofail.find(dest_id) != globalConnections_nofail.end()) + return true; + if (terminalConnections_nofail.find(dest_id) != terminalConnections_nofail.end()) + return true; + + return false; + } + + // //The below version is safer but slow as heck. + // map > the_map; + // map >::iterator map_it; + + // if (include_failed) + // { + // if (type == CONN_LOCAL) + // the_map = intraGroupConnections; + // else if (type == CONN_GLOBAL) + // the_map = globalConnections; + // else if (type == CONN_TERMINAL) + // the_map = terminalConnections; + // else if (type == CONN_INJECTION) + // the_map = injectionConnections; + // else + // assert(false); + // } + // else { + // if (type == CONN_LOCAL) + // the_map = intraGroupConnections_nofail; + // else if (type == CONN_GLOBAL) + // the_map = globalConnections_nofail; + // else if (type == CONN_TERMINAL) + // the_map = terminalConnections_nofail; + // else if (type == CONN_INJECTION) + // the_map = injectionConnections_nofail; + // else + // assert(false); + // } + + // vector::iterator vec_it; + // map_it = the_map.find(dest_id); + // if (map_it != the_map.end()) + // { + // if (map_it->second.size() > 0) //verify that there is at least one connection - empty vector shouldn't count + // return true; + // } + // return false; +} + +bool DragonflyConnectionManager::is_any_connection_to(int dest_global_id) +{ + return is_any_connection_to(dest_global_id, false); +} + +bool DragonflyConnectionManager::is_any_connection_to(int dest_global_id, bool include_failed) +{ + int local_id = dest_global_id % _num_routers_per_group; + if (is_connected_to_by_type(local_id, CONN_LOCAL, include_failed)) + return true; + if (is_connected_to_by_type(dest_global_id, CONN_GLOBAL, include_failed)) + return true; + if (is_connected_to_by_type(dest_global_id, CONN_TERMINAL, include_failed)) + return true; + if (is_connected_to_by_type(dest_global_id, CONN_INJECTION, include_failed)) + return true; + return false; +} + +int DragonflyConnectionManager::get_total_used_ports(bool account_for_failed) +{ + int sum = 0; + sum = _used_intra_ports + _used_inter_ports + _used_terminal_ports; + if (account_for_failed) + sum -= (_failed_intra_ports + _failed_inter_ports + _failed_terminal_ports); + return sum; +} + +int DragonflyConnectionManager::get_total_used_ports() +{ + return get_total_used_ports(true); +} + +int DragonflyConnectionManager::get_used_ports_for(ConnectionType type, bool account_for_failed) +{ + switch (type) + { + case CONN_LOCAL: + return _used_intra_ports - (_failed_intra_ports * account_for_failed); + break; + case CONN_GLOBAL: + return _used_inter_ports - (_failed_inter_ports * account_for_failed); + break; + case CONN_TERMINAL: + return _used_terminal_ports - (_failed_terminal_ports * account_for_failed); + break; + case CONN_INJECTION: + return _used_injection_ports - (_failed_injection_ports * account_for_failed); + break; + default: + assert(false); + // TW_ERROR(TW_LOC, "get_used_ports_for(type): Undefined connection type\n"); + } +} + +int DragonflyConnectionManager::get_used_ports_for(ConnectionType type) +{ + return get_used_ports_for(type, true); +} + +ConnectionType DragonflyConnectionManager::get_port_type(int port_num) +{ + return _portMap[port_num].conn_type; +} + +bool DragonflyConnectionManager::get_port_failed_status(int port_num) +{ + return _portMap[port_num].is_failed; +} + +vector< Connection > DragonflyConnectionManager::get_connections_to_gid(int dest_gid, ConnectionType type) +{ + return get_connections_to_gid(dest_gid, type, false); +} + +vector< Connection > DragonflyConnectionManager::get_connections_to_gid(int dest_gid, ConnectionType type, bool include_failed) +{ + vector conn_vec; + try { + if (include_failed) + { + switch (type) + { + case CONN_LOCAL: + return intraGroupConnectionsGID.at(dest_gid); + break; + case CONN_GLOBAL: + return globalConnections.at(dest_gid); + break; + case CONN_TERMINAL: + return terminalConnections.at(dest_gid); + break; + case CONN_INJECTION: + return injectionConnections.at(dest_gid); + break; + default: + assert(false); + // TW_ERROR(TW_LOC, "get_connections(type): Undefined connection type\n"); + } + } + else + { + switch (type) + { + case CONN_LOCAL: + return intraGroupConnectionsGID_nofail.at(dest_gid); + break; + case CONN_GLOBAL: + return globalConnections_nofail.at(dest_gid); + break; + case CONN_TERMINAL: + return terminalConnections_nofail.at(dest_gid); + break; + case CONN_INJECTION: + return injectionConnections_nofail.at(dest_gid); + break; + default: + assert(false); + // TW_ERROR(TW_LOC, "get_connections(type): Undefined connection type\n"); + } + } + } catch (exception e) + { + return vector(); //so we don't accidentally add a key with [] + } +} + +vector< Connection > DragonflyConnectionManager::get_connections_to_group(int dest_group_id) +{ + return get_connections_to_group(dest_group_id, false); +} + +vector< Connection > DragonflyConnectionManager::get_connections_to_group(int dest_group_id, bool include_failed) +{ + try { + if(include_failed) + { + return _connections_to_groups_map.at(dest_group_id); + } + else + { + return _connections_to_groups_map_nofail.at(dest_group_id); + } + } catch (exception e) { + return vector(); //so we don't accidentally add a key with [] + } +} + +vector< Connection > DragonflyConnectionManager::get_connections_by_type(ConnectionType type) +{ + return get_connections_by_type(type, false); +} + +vector< Connection > DragonflyConnectionManager::get_connections_by_type(ConnectionType type, bool include_failed) +{ + try { + if(include_failed) + return _all_conns_by_type_map.at(type); + else + return _all_conns_by_type_map_nofail.at(type); + } catch (exception e) { + return vector(); //so we don't accidentally add a key with [] + } +} + +vector< int > DragonflyConnectionManager::get_connected_group_ids() +{ + return get_connected_group_ids(false); +} + +vector< int > DragonflyConnectionManager::get_connected_group_ids(bool include_failed) +{ + if (include_failed) + return _other_groups_i_connect_to; + else + return _other_groups_i_connect_to_nofail; +} + +void DragonflyConnectionManager::solidify_connections() +{ + //--connections to group + for(map >::iterator it = globalConnections.begin(); it != globalConnections.end(); it++) + { + vector< Connection >::iterator vec_it = it->second.begin(); + for(; vec_it != it->second.end(); vec_it++) + { + int dest_group_id = vec_it->dest_group_id; + _connections_to_groups_map[dest_group_id].push_back(*vec_it); + } + } + + //other groups i connect to + for(map >::iterator it = _connections_to_groups_map.begin(); it != _connections_to_groups_map.end(); it++) + { + if(it->second.size() > 0) //empty vectors can be inserted if [] is used on a non-exist key + _other_groups_i_connect_to.push_back(it->first); + } + + //--get connections by type + map< int, vector< Connection > > theMap; + for ( int enum_int = CONN_LOCAL; enum_int != CONN_INJECTION + 1; enum_int++ ) + { + switch (enum_int) + { + case CONN_LOCAL: + theMap = intraGroupConnections; + break; + case CONN_GLOBAL: + theMap = globalConnections; + break; + case CONN_TERMINAL: + theMap = terminalConnections; + break; + case CONN_INJECTION: + theMap = injectionConnections; + 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; + } + + + // make copies of data structures but without failed links ----------------------------------------- + map< int, vector< Connection > >::iterator it; + for(it = intraGroupConnections.begin(); it != intraGroupConnections.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + intraGroupConnections_nofail[id].push_back(*vec_it); + } + } + + for(it = intraGroupConnectionsGID.begin(); it != intraGroupConnectionsGID.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + intraGroupConnectionsGID_nofail[id].push_back(*vec_it); + } + } + + for(it = globalConnections.begin(); it != globalConnections.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + globalConnections_nofail[id].push_back(*vec_it); + } + } + + for(it = terminalConnections.begin(); it != terminalConnections.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + terminalConnections_nofail[id].push_back(*vec_it); + } + } + + for(it = injectionConnections.begin(); it != injectionConnections.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + injectionConnections_nofail[id].push_back(*vec_it); + } + } + + for(it = _connections_to_groups_map.begin(); it != _connections_to_groups_map.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + _connections_to_groups_map_nofail[id].push_back(*vec_it); + } + } + + for(it = _connections_to_groups_map_nofail.begin(); it != _connections_to_groups_map_nofail.end(); it++) + { + if(it->second.size() > 0) //empty vectors can be inserted if [] is used on a non-exist key + { + add_as_if_set_int(it->first, _other_groups_i_connect_to_nofail); + } + } + + + for(it = _all_conns_by_type_map.begin(); it != _all_conns_by_type_map.end(); it++) + { + int id = it->first; + vector conns_to_id = it->second; + vector< Connection >::iterator vec_it; + for(vec_it = conns_to_id.begin(); vec_it != conns_to_id.end(); vec_it++) + { + if(vec_it->is_failed == 0) + _all_conns_by_type_map_nofail[id].push_back(*vec_it); + } + } + + for(it = _routed_connections_to_group_map.begin(); it != _routed_connections_to_group_map.end(); it++) + { + int group_id = it->first; + vector conns_to_group = it->second; + vector::iterator vec_it; + for(vec_it = conns_to_group.begin(); vec_it != conns_to_group.end(); vec_it++) + { + vector< Connection > local_conns = get_connections_to_gid(vec_it->src_gid, CONN_LOCAL, true); + if (local_conns.size() > 1) + _next_hop_routed_connections_to_group_map[group_id].insert(_next_hop_routed_connections_to_group_map[group_id].end(), local_conns.begin(), local_conns.end()); + + local_conns = get_connections_to_gid(vec_it->src_gid, CONN_LOCAL, false); + if (local_conns.size() > 1) + _next_hop_routed_connections_to_group_map_nofail[group_id].insert(_next_hop_routed_connections_to_group_map_nofail[group_id].end(), local_conns.begin(), local_conns.end()); + + if(vec_it->is_failed == 0) + _routed_connections_to_group_map_nofail[group_id].push_back(*vec_it); + } + } + + for(it = _routed_connections_to_group_map.begin(); it != _routed_connections_to_group_map.end(); it++) + { + int group_id = it->first; + vector conns_to_group = it->second; + vector::iterator vec_it; + for(vec_it = conns_to_group.begin(); vec_it != conns_to_group.end(); vec_it++) + { + int src_gid = vec_it->src_gid; + add_as_if_set_int(src_gid, _routed_router_gids_to_group_map[group_id]); + + if (vec_it->is_failed == 0) { + add_as_if_set_int(src_gid, _routed_router_gids_to_group_map_nofail[group_id]); + } + } + } + + for(it = _routed_connections_to_group_map_nofail.begin(); it != _routed_connections_to_group_map_nofail.end(); it++) + { + int group_id = it->first; + vector conns_to_group = it->second; + vector::iterator vec_it; + for(vec_it = conns_to_group.begin(); vec_it != conns_to_group.end(); vec_it++) + { + if (is_connected_to_by_type(vec_it->src_gid, CONN_LOCAL)) + { + _accessible_group_ids_nofail.push_back(group_id); + break; + } + } + } + vector::iterator vec_it; + for(vec_it = _other_groups_i_connect_to_nofail.begin(); vec_it != _other_groups_i_connect_to_nofail.end(); vec_it++) + { + add_as_if_set_int(*vec_it,_accessible_group_ids_nofail); + } + + is_solidified = true; +} + +bool DragonflyConnectionManager::check_is_solidified() +{ + return is_solidified; +} + +void DragonflyConnectionManager::print_connections() +{ + if(_manType == MAN_ROUTER) + printf("Connections for Router: %d ---------------------------------------\n",_source_id_global); + else + printf("Connections for Terminal: %d -------------------------------------\n",_source_id_global); + + int ports_printed = 0; + map::iterator it = _portMap.begin(); + for(; it != _portMap.end(); it++) + { + if ( (ports_printed == 0) && (_used_intra_ports > 0) ) + { + printf(" -- Intra-Group Connections -- \n"); + printf(" Port | Dest_ID | Group | Link Type | Rail ID | Fail Status\n"); + } + if ( (ports_printed == _used_intra_ports) && (_used_inter_ports > 0) ) + { + printf(" -- Inter-Group Connections -- \n"); + printf(" Port | Dest_ID | Group | Link Type | Rail ID | Fail Status\n"); + } + if ( (ports_printed == _used_intra_ports + _used_inter_ports) && (_used_terminal_ports > 0) ) + { + printf(" -- Terminal Connections -- \n"); + printf(" Port | Dest_ID | Group | Link Type | Rail ID | Fail Status\n"); + } + if ( (ports_printed == _used_intra_ports + _used_inter_ports + _used_terminal_ports) && (_used_injection_ports > 0) ) + { + printf(" -- Injection Connections -- \n"); + printf(" Port | Dest_ID | Group | Link Type | Rail ID | Fail Status\n"); + } + + 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 - LOCAL - %d - %d\n", port_num, id, gid, group_id,it->second.rail_or_planar_id,it->second.is_failed); + + } + else if (get_port_type(port_num) == CONN_GLOBAL) { + id = it->second.dest_gid; + printf(" %d -> %d : %d - GLOBAL - %d - %d\n", port_num, id, group_id,it->second.rail_or_planar_id,it->second.is_failed); + } + else if (get_port_type(port_num) == CONN_TERMINAL) { + id = it->second.dest_gid; + printf(" %d -> %d : %d - TERMINAL - %d - %d\n", port_num, id, group_id,it->second.rail_or_planar_id,it->second.is_failed); + } + else if(get_port_type(port_num) == CONN_INJECTION) { + id = it->second.dest_gid; + printf(" %d -> %d : %d - INJECTION - %d - %d\n", port_num, id, group_id,it->second.rail_or_planar_id,it->second.is_failed); + } + + ports_printed++; + } +} + +// void filter_valid_nexts_from_conns(vector< Connection >& conns, int local_hops_used, int global_hops_used, int fdest_router_id) +// { +// IsPathInvalid::erase_where(conns, IsPathInvalid(&netMan, fdest_router_id, local_hops_used, global_hops_used)); +// } + +// IsPathInvalid::IsPathInvalid(NetworkManager *net, int final_dest_router_id, int local_hops_per_group, int global_hops) +// { +// netMan = net; +// fdest_router_id = final_dest_router_id; +// available_local_hops_per_group = netMan->get_max_local_hops() - local_hops_per_group; +// available_global_hops = netMan->get_max_global_hops() - global_hops; +// } + + +// bool IsPathInvalid::operator()(Connection conn) const { +// if (conn.conn_type == CONN_LOCAL) { +// if (netMan->is_valid_path_between(conn.dest_gid, fdest_router_id, available_local_hops_per_group-1, available_global_hops)) +// return false; +// return true; +// } +// else if(conn.conn_type == CONN_GLOBAL) { +// if (netMan->is_valid_path_between(conn.dest_gid, fdest_router_id, netMan->get_max_local_hops(), available_global_hops-1)) +// return false; +// return true; +// } +// else { +// return false; +// } +// } + +// vector::iterator IsPathInvalid::erase_where(vector conns, IsPathInvalid&& f) +// { +// return conns.erase(std::remove_if(conns.begin(), +// conns.end(), +// std::forward(f)), +// conns.end()); +// } + +// template +// vector::iterator IsPathInvalid::erase_where(vector conns, F&& f) +// { +// return conns.erase(std::remove_if(conns.begin(), +// conns.end(), +// std::forward(f)), +// conns.end()); +// } \ No newline at end of file diff --git a/src/networks/model-net/simplenet-upd.c b/src/networks/model-net/simplenet-upd.c index 1b0c7e92..5b5edc78 100644 --- a/src/networks/model-net/simplenet-upd.c +++ b/src/networks/model-net/simplenet-upd.c @@ -17,8 +17,8 @@ #include "codes/codes.h" #include "codes/net/simplenet-upd.h" -#define CATEGORY_NAME_MAX 16 -#define CATEGORY_MAX 12 +// #define CATEGORY_NAME_MAX 16 +// #define CATEGORY_MAX 12 #define LP_CONFIG_NM (model_net_lp_config_names[SIMPLENET]) #define LP_METHOD_NM (model_net_method_names[SIMPLENET]) diff --git a/src/networks/model-net/simplep2p.c b/src/networks/model-net/simplep2p.c index 65843897..e7609870 100644 --- a/src/networks/model-net/simplep2p.c +++ b/src/networks/model-net/simplep2p.c @@ -17,8 +17,8 @@ #include "codes/codes.h" #include "codes/net/simplep2p.h" -#define CATEGORY_NAME_MAX 16 -#define CATEGORY_MAX 12 +// #define CATEGORY_NAME_MAX 16 +// #define CATEGORY_MAX 12 #define SIMPLEP2P_DEBUG 0 diff --git a/src/util/codes_mapping.c b/src/util/codes_mapping.c index f39be0d2..9a8554ba 100644 --- a/src/util/codes_mapping.c +++ b/src/util/codes_mapping.c @@ -8,6 +8,7 @@ * CODES custom mapping file for ROSS */ #include "codes/codes_mapping.h" +#include "codes/congestion-controller-core.h" #define CODES_MAPPING_DEBUG 0 @@ -98,6 +99,22 @@ int codes_mapping_get_group_reps(const char* group_name) return -1; } +// returns the total number of LPs defined in LPGROUPS +// this lets us define an auxillary LP group for one off LPs +// like the supervisory controller +int codes_mapping_get_lpgroups_lp_count() +{ + tw_lpid total_count = 0; + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + total_count += (lpt->count * lpg->repetitions); + } + } + return total_count; +} + int codes_mapping_get_lp_count( const char * group_name, int ignore_repetitions, @@ -475,8 +492,12 @@ static void codes_mapping_init(void) ross_lid = lpid - lp_start; kpid = ross_lid % g_tw_nkp; pe = g_tw_pe; - codes_mapping_get_lp_info(ross_gid, NULL, &grp_id, lp_type_name, - &lpt_id, NULL, &rep_id, &offset); + + codes_mapping_get_lp_info(ross_gid, NULL, &grp_id, lp_type_name, + &lpt_id, NULL, &rep_id, &offset); + + + #if CODES_MAPPING_DEBUG printf("lp:%lu --> kp:%lu, pe:%llu\n", ross_gid, kpid, pe->id); #endif @@ -521,6 +542,7 @@ void codes_mapping_setup_with_seed_offset(int offset) for (lpt = 0; lpt < lpconf.lpgroups[grp].lptypes_count; lpt++) lps_per_pe_floor += (lpconf.lpgroups[grp].lptypes[lpt].count * lpconf.lpgroups[grp].repetitions); } + tw_lpid global_nlps = lps_per_pe_floor; lps_leftover = lps_per_pe_floor % pes; lps_per_pe_floor /= pes; @@ -547,6 +569,7 @@ void codes_mapping_setup_with_seed_offset(int offset) // we increment the number of RNGs used to let codes_local_latency use the // last one g_tw_nRNG_per_lp++; + g_tw_nRNG_per_lp++; //Congestion Control gets its own RNG - second to last (CLL is last) tw_define_lps(codes_mapping_get_lps_for_pe(), message_size); @@ -559,7 +582,7 @@ void codes_mapping_setup_with_seed_offset(int offset) for (tw_lpid l = 0; l < g_tw_nlp; l++){ for (unsigned int i = 0; i < g_tw_nRNG_per_lp; i++){ tw_rand_initial_seed(&g_tw_lp[l]->rng[i], (g_tw_lp[l]->gid + - global_nlps * offset) * g_tw_nRNG_per_lp + i); + global_nlps * offset) * g_tw_nRNG_per_lp + i, NULL); } } } diff --git a/src/util/congestion-controller.C b/src/util/congestion-controller.C new file mode 100644 index 00000000..a0dab10c --- /dev/null +++ b/src/util/congestion-controller.C @@ -0,0 +1,1202 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERMANENT_ABATEMENT 1 +#define OUTPUT_BANDWIDTHS 0 + +using namespace std; + +struct codes_jobmap_ctx *jobmap_ctx; +static int is_jobmap_set = 0; + +/* global variables for codes mapping */ +static char lp_group_name[MAX_NAME_LENGTH]; +static int mapping_grp_id, mapping_type_id, mapping_rep_id, mapping_offset; + +static int network_id = 0; +static double cc_bandwidth_monitoring_window = 10000; +static int cc_bandwidth_rolling_window_count = 5; + +unsigned long long stalled_packet_counter = 0; +unsigned long long stalled_nic_counter = 0; + +/************* DEFINITIONS ****************************************/ +int g_congestion_control_enabled; +tw_stime g_congestion_control_notif_latency = 0; + +const tw_optdef cc_app_opt [] = +{ + TWOPT_GROUP("Congestion Control"), + TWOPT_STIME("cc_notif_latency", g_congestion_control_notif_latency, "latency for congestion control notifications"), + TWOPT_END() +}; + +static char terminal_lp_name[128]; +static char router_lp_name[128]; + +// definition of class methods of Portchan_node class defined in congestion-controller-model.h +Portchan_node::Portchan_node(portchan_node_type pnt, int router_radix, int vcs_per_port) +{ + type = pnt; + packet_count = 0; + is_congested = false; + + switch(type) + { + case ROOT: + for(int i = 0; i < router_radix; i++) + { + Portchan_node* child = new Portchan_node(PORT, router_radix, vcs_per_port); //delete done in deconstructor + children.push_back(child); + } + break; + case PORT: + for(int i = 0; i < vcs_per_port; i++) + { + Portchan_node* child = new Portchan_node(VC, router_radix, vcs_per_port); //delete done in deconstructor + children.push_back(child); + } + break; + case VC://do nothing else + break; + default: + tw_error(TW_LOC, "Portchan_node enqueue: Invalid node type\n"); + } +} + +Portchan_node::~Portchan_node() +{ + //type and packet_count are primitives + term_count_map.clear(); //not new'd but just to be safe lets clear it + for(int i = 0; i < children.size(); i++) + { + delete children[i]; //deconstruct recursively + } +} + +unsigned long long Portchan_node::get_packet_count() +{ + return packet_count; +} + +unsigned long long Portchan_node::get_packet_count_from_term(unsigned int term_id) +{ + try { + return term_count_map.at(term_id); + } catch (exception e) { + return 0; + } +} + +unsigned long long Portchan_node::get_packet_count_by_port(int port_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->get_packet_count(); +} + +unsigned long long Portchan_node::get_packet_count_by_port_from_term(int port_no, unsigned int term_id) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->get_packet_count_from_term(term_id); +} + +unsigned long long Portchan_node::get_packet_count_by_port_vc(int port_no, int vc_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->get_packet_count(); +} + +unsigned long long Portchan_node::get_packet_count_by_port_vc_from_term(int port_no, int vc_no, unsigned int term_id) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->get_packet_count_from_term(term_id); +} + +map Portchan_node::get_term_count_map() +{ + return term_count_map; +} + +map Portchan_node::get_app_count_map() +{ + return app_count_map; +} + +map Portchan_node::get_term_count_map_by_port(int port_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->get_term_count_map(); +} + +map Portchan_node::get_app_count_map_by_port(int port_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->get_app_count_map(); +} + +map Portchan_node::get_term_count_map_by_port_vc(int port_no, int vc_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->get_term_count_map(); +} + +map Portchan_node::get_app_count_map_by_port_vc(int port_no, int vc_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->get_app_count_map(); +} + +map Portchan_node::get_term_count_map_from_app(int app_id) +{ + return app_to_terminal_counter.at(app_id); +} + +map Portchan_node::get_term_count_map_by_port_from_app(int port_no, int app_id) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->get_term_count_map_from_app(app_id); +} + +map Portchan_node::get_term_count_map_by_port_vc_from_app(int port_no, int vc_no, int app_id) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->get_term_count_map_from_app(app_id); +} + +bool Portchan_node::is_router_congested() +{ + return is_congested; +} + +bool Portchan_node::is_port_congested(int port_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->is_congested; +} + +bool Portchan_node::is_port_vc_congested(int port_no, int vc_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->is_congested; +} + +void Portchan_node::set_router_congestion_state(bool new_is_congested) +{ + is_congested = new_is_congested; +} + +void Portchan_node::set_port_congestion_state(int port_no, bool new_is_congested) +{ + children[port_no]->is_congested = new_is_congested; +} + +void Portchan_node::set_port_vc_congested(int port_no, int vc_no, bool new_is_congested) +{ + children[port_no]->children[vc_no]->is_congested = new_is_congested; +} + +void Portchan_node::set_next_possible_router_normal_time(tw_stime time) +{ + next_possible_normal_time = time; +} + +void Portchan_node::set_next_possible_port_normal_time(int port_no, tw_stime time) +{ + children[port_no]->next_possible_normal_time = time; +} + +void Portchan_node::set_next_possible_vc_normal_time(int port_no, int vc_no, tw_stime time) +{ + children[port_no]->children[vc_no]->next_possible_normal_time = time; +} + +tw_stime Portchan_node::get_next_possible_router_normal_time() +{ + return next_possible_normal_time; +} + +tw_stime Portchan_node::get_next_possible_port_normal_time(int port_no) +{ + return children[port_no]->next_possible_normal_time; +} + +tw_stime Portchan_node::get_next_possible_vc_normal_time(int port_no, int vc_no) +{ + return children[port_no]->children[vc_no]->next_possible_normal_time; +} + +void Portchan_node::mark_abated_terminal(unsigned int term_id) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + abated_terminals_this_node.emplace(term_id); +} + + +void Portchan_node::mark_abated_terminal(int port_no, unsigned int term_id) +{ + switch(type) + { + case ROOT: + abated_terminal_child_counter[term_id] += 1; + children[port_no]->mark_abated_terminal(port_no, term_id); + break; + case PORT: + abated_terminals_this_node.emplace(term_id); + break; + case VC://do nothing else + break; + default: + tw_error(TW_LOC, "Portchan_node enqueue: Invalid node type\n"); + } +} + +void Portchan_node::mark_abated_terminal(int port_no, int vc_no, unsigned int term_id) +{ + switch(type) + { + case ROOT: + abated_terminal_child_counter[term_id] += 1; + children[port_no]->mark_abated_terminal(port_no, vc_no, term_id); + break; + case PORT: + abated_terminal_child_counter[term_id] += 1; + children[vc_no]->mark_abated_terminal(port_no, vc_no, term_id); + break; + case VC: + abated_terminals_this_node.emplace(term_id); + break; + default: + tw_error(TW_LOC, "Portchan_node enqueue: Invalid node type\n"); + } +} + +void Portchan_node::mark_unabated_terminal(unsigned int term_id) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + abated_terminals_this_node.erase(term_id); +} + +void Portchan_node::mark_unabated_terminal(int port_no, unsigned int term_id) +{ + switch(type) + { + case ROOT: + abated_terminal_child_counter[term_id] -= 1; + if(abated_terminal_child_counter[term_id] == 0) + abated_terminal_child_counter.erase(term_id); + children[port_no]->mark_unabated_terminal(port_no, term_id); + break; + case PORT: + abated_terminals_this_node.erase(term_id); + break; + case VC://do nothing else + break; + default: + tw_error(TW_LOC, "Portchan_node enqueue: Invalid node type\n"); + } +} + +void Portchan_node::mark_unabated_terminal(int port_no, int vc_no, unsigned int term_id) +{ + switch(type) + { + case ROOT: + abated_terminal_child_counter[term_id] -= 1; + if(abated_terminal_child_counter[term_id] == 0) + abated_terminal_child_counter.erase(term_id); + children[port_no]->mark_unabated_terminal(port_no, vc_no, term_id); + break; + case PORT: + abated_terminal_child_counter[term_id] -= 1; + if(abated_terminal_child_counter[term_id] == 0) + abated_terminal_child_counter.erase(term_id); + children[vc_no]->mark_unabated_terminal(port_no, vc_no, term_id); + break; + case VC: + abated_terminals_this_node.erase(term_id); + break; + default: + tw_error(TW_LOC, "Portchan_node enqueue: Invalid node type\n"); + } +} + +bool Portchan_node::is_abated_terminal(unsigned int term_id) +{ + if (abated_terminals_this_node.count(term_id)) + return true; + else + { + try { + if (abated_terminal_child_counter.at(term_id) > 0) + return true; + } catch (exception e) + { + return false; + } + } + return false; +} + +set Portchan_node::get_abated_terminals() +{ + return abated_terminals_this_node; +} + +set Portchan_node::get_abated_terminals(int port_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->get_abated_terminals(); +} + +set Portchan_node::get_abated_terminals(int port_no, int vc_no) +{ + if(type != ROOT) + tw_error(TW_LOC, "Portchan_node : Invalid node type for this action\n"); + + return children[port_no]->children[vc_no]->get_abated_terminals(); +} + + +void Portchan_node::enqueue_packet(unsigned int packet_size, int port_no, int vc_no, unsigned int term_id, unsigned int app_id) +{ + packet_count += packet_size; + term_count_map[term_id] += packet_size; + app_count_map[app_id] += packet_size; + app_to_terminal_counter[app_id][term_id] += packet_size; + + switch(type) + { + case ROOT: + children[port_no]->enqueue_packet(packet_size, port_no, vc_no, term_id, app_id); + break; + case PORT: + children[vc_no]->enqueue_packet(packet_size, port_no, vc_no, term_id, app_id); + break; + case VC://do nothing else + break; + default: + tw_error(TW_LOC, "Portchan_node enqueue: Invalid node type\n"); + } +} + +void Portchan_node::dequeue_packet(unsigned int packet_size, int port_no, int vc_no, unsigned int term_id, unsigned int app_id) +{ + assert(packet_count >= packet_size); + + packet_count -= packet_size; + term_count_map[term_id] -= packet_size; + if(term_count_map.at(term_id)== 0) + term_count_map.erase(term_id); + app_count_map[app_id] -= packet_size; + if(app_count_map.at(app_id) == 0) + app_count_map.erase(app_id); + + assert(app_to_terminal_counter[app_id][term_id] >= packet_size); + app_to_terminal_counter[app_id][term_id] -= packet_size; + if(app_to_terminal_counter.at(app_id).at(term_id) == 0) + app_to_terminal_counter.at(app_id).erase(term_id); + if(app_to_terminal_counter.at(app_id).begin() == app_to_terminal_counter.at(app_id).end()) + app_to_terminal_counter.erase(app_id); + + switch(type) + { + case ROOT: + children[port_no]->dequeue_packet(packet_size, port_no, vc_no, term_id, app_id); + break; + case PORT: + children[vc_no]->dequeue_packet(packet_size, port_no, vc_no, term_id, app_id); + break; + case VC://do nothing else + break; + default: + tw_error(TW_LOC, "Portchan_node dequeue: Invalid node type\n"); + } +} + +/************* GLOBALS ********************************************/ +static map< tw_lpid, int > router_lpid_to_id_map = map(); +static map< tw_lpid, int > terminal_lpid_to_id_map = map(); +static map< int, tw_lpid > router_id_to_lpid_map = map(); +static map< int, tw_lpid > terminal_id_to_lpid_map = map(); + +static string congestion_pattern_set_filepath; +static set congestion_pattern_set = set(); + +static string decongestion_pattern_set_filepath; +static set decongestion_pattern_set = set(); + +/************* PROTOTYPES *****************************************/ + + + + + + +/************* HELPER FUNCTIONS ***********************************/ + +/* convert GiB/s and bytes to ns */ +static tw_stime bytes_to_ns(uint64_t bytes, double GB_p_s) +{ + tw_stime time; + + /* bytes to GB */ + time = ((double)bytes)/(1024.0*1024.0*1024.0); + /* GiB to s */ + time = time / GB_p_s; + /* s to ns */ + time = time * 1000.0 * 1000.0 * 1000.0; + + return(time); +} + +double cc_tw_rand_unif(tw_lp *lp) +{ + //based on what was defined in codes_mapping.c, congestion control uses second to last RNG on the LP + assert(g_tw_nRNG_per_lp > 2); //0 for model, 1 for CC, 2 for codes local latency + int cc_rng_id = g_tw_nRNG_per_lp - 2; + return tw_rand_unif(&lp->rng[cc_rng_id]); +} + +double cc_tw_rand_reverse_unif(tw_lp *lp) +{ + //based on what was defined in codes_mapping.c, congestion control uses second to last RNG on the LP + assert(g_tw_nRNG_per_lp > 2); //0 for model, 1 for CC, 2 for codes local latency + int cc_rng_id = g_tw_nRNG_per_lp - 2; + return tw_rand_reverse_unif(&lp->rng[cc_rng_id]); +} + +congestion_control_message* cc_msg_rc_storage_create() +{ + congestion_control_message *msg = (congestion_control_message*)calloc(1, sizeof(congestion_control_message)); + return msg; +} + +void cc_msg_rc_storage_delete(void * ptr) +{ + congestion_control_message *rc_msg = (congestion_control_message*)ptr; + if (rc_msg->size_abated > 0) + free(rc_msg->danger_rc_abated); + if (rc_msg->size_deabated > 0) + free(rc_msg->danger_rc_deabated); + free(ptr); +} + +void congestion_control_register_terminal_lpname(char lp_name[]) +{ + strcpy(terminal_lp_name, lp_name); +} + +void congestion_control_register_router_lpname(char lp_name[]) +{ + strcpy(router_lp_name, lp_name); +} + +int congestion_control_set_jobmap(struct codes_jobmap_ctx *ctx, int net_id) +{ + // if (g_congestion_control_enabled == 0) + // return -1; + + if (ctx == NULL) { + // tw_printf("Congestion Control: No jobmap passed to control module - Causation Detection Not Enabled") + return -2; + } + else { + jobmap_ctx = ctx; + network_id = net_id; + is_jobmap_set = 1; + return 0; + } +} + +int congestion_control_is_jobmap_set() +{ + return is_jobmap_set; +} + +struct codes_jobmap_ctx* congestion_control_get_jobmap() +{ + if (is_jobmap_set == 0) + tw_error(TW_LOC,"Codes Jobmap was never passed to the congestion controller\n"); + else + return jobmap_ctx; +} + +int congestion_control_get_job_count() +{ + if (is_jobmap_set == 0) + return 1; + else + return codes_jobmap_get_num_jobs(jobmap_ctx); +} + +struct pair_hash { + inline std::size_t operator()(const std::pair & v) const { + return v.first*28657+v.second; + } +}; + +//Router Local Controller +void cc_router_local_controller_init(rlc_state *s, tw_lp* lp, int total_terminals, int router_id, int radix, int num_vcs_per_port, int* vc_sizes, double* bandwidths, int* workload_finished_flag_ptr) +{ + // printf("CC LOCAL INIT!\n"); + s->params = (cc_param*)calloc(1, sizeof(cc_param)); + cc_param *p = s->params; + + p->router_radix = radix; + p->router_vc_per_port = num_vcs_per_port; + s->router_vc_sizes_on_each_port = vc_sizes; + s->router_bandwidths_on_each_port = bandwidths; + + int rc = configuration_get_value_double(&config, "PARAMS", "cc_single_port_congestion_threshold", NULL, &p->single_port_congestion_threshold); + if(rc) { + p->single_port_congestion_threshold = .30; + } + + rc = configuration_get_value_double(&config, "PARAMS", "cc_single_port_decongestion_threshold", NULL, &p->single_port_decongestion_threshold); + if(rc) { + p->single_port_decongestion_threshold = .05; + } + + rc = configuration_get_value_double(&config, "PARAMS", "cc_single_port_aggressor_usage_threshold", NULL, &p->single_port_aggressor_usage_threshold); + if(rc) { + p->single_port_aggressor_usage_threshold = .10; + } + + rc = configuration_get_value_double(&config, "PARAMS", "cc_minimum_abatement_active_time", NULL, &p->minimum_abatement_time); + if(rc) { + p->minimum_abatement_time = 10000000; + } + + p->notification_latency = g_congestion_control_notif_latency; + + s->router_id = router_id; + s->lp = lp; + // s->vc_occupancy_ptr = &vc_occupancy; + // s->port_vc_to_term_count_map = map,map >(); + + s->workloads_finished_flag_ptr = workload_finished_flag_ptr; + s->output_ports = set(); + s->packet_counting_tree = new Portchan_node(ROOT, radix, num_vcs_per_port); +} + +void cc_router_local_controller_add_output_port(rlc_state *s, int port_no) +{ + s->output_ports.insert(port_no); +} + +void cc_router_local_congestion_event(rlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + switch(msg->type) + { + default: + tw_error(TW_LOC, "Invalid event at cc router local congestion event"); + break; + } +} + +void cc_router_local_congestion_event_rc(rlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + switch(msg->type) + { + default: + tw_error(TW_LOC, "Invalid event at cc router local congestion event rc"); + break; + } +} + +void cc_router_local_congestion_event_commit(rlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + switch(msg->type) + { + default: + tw_error(TW_LOC, "Invalid event at cc router local congestion event commit"); + break; + } +} + +void cc_router_received_packet(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg) +{ + // s->port_vc_to_term_count_map[make_pair(port_no, vc_no)][term_id]++; + if (s->output_ports.size() > 0 && s->output_ports.count(port_no) > 0) { + s->packet_counting_tree->enqueue_packet(packet_size, port_no, vc_no, term_id, app_id); + + double cur_expire_time = s->packet_counting_tree->get_next_possible_port_normal_time(port_no); + rc_msg->saved_expire_time = cur_expire_time; + + if (s->packet_counting_tree->is_port_congested(port_no) == true) { + // Then abatement for this port is already active, we need to see if this is a packet from a new aggresssor + // regardless, we also need to extend the abatement policy + + if (s->packet_counting_tree->is_abated_terminal(term_id) == false) + { + int this_app_occupancy = s->packet_counting_tree->get_app_count_map_by_port(port_no)[app_id]; + unsigned long long port_occupancy = s->packet_counting_tree->get_packet_count_by_port(port_no); + if ((this_app_occupancy / port_occupancy) >= s->params->single_port_aggressor_usage_threshold) { + //then we haven't yet abated the terminal that send this message and we are currently in congestion + rc_msg->received_new_while_congested = true; + rc_msg->saved_term_id = term_id; + + //need to send abatement to it + tw_lpid term_lpgid = codes_mapping_get_lpid_from_relative(term_id, NULL, terminal_lp_name, NULL, 0); + congestion_control_message *c_msg; + tw_event *e = model_net_method_congestion_event(term_lpgid, s->params->notification_latency, s->lp, (void**)&c_msg, NULL); + c_msg->type = CC_SIGNAL_ABATE; + c_msg->app_id = app_id; + tw_event_send(e); + + s->packet_counting_tree->mark_abated_terminal(port_no, term_id); //increments the abatement counter + } + } + + s->packet_counting_tree->set_next_possible_port_normal_time(port_no, cur_expire_time+bytes_to_ns(packet_size, s->router_bandwidths_on_each_port[port_no])); + } + else { //TODO NOTE: this if else only is valid if we're only monitoring ports + cc_router_congestion_check(s, lp, port_no, vc_no, rc_msg); + } + } +} + +void cc_router_received_packet_rc(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg) +{ + if (s->output_ports.size() > 0 && s->output_ports.count(port_no) > 0) { + cc_router_congestion_check_rc(s, lp, port_no, vc_no, rc_msg); + + if (rc_msg->received_new_while_congested == true) + { + s->packet_counting_tree->mark_unabated_terminal(port_no, rc_msg->saved_term_id); + } + + s->packet_counting_tree->set_next_possible_port_normal_time(port_no, rc_msg->saved_expire_time); + + + s->packet_counting_tree->dequeue_packet(packet_size, port_no, vc_no, term_id, app_id); + } +} + +void cc_router_forwarded_packet(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg) +{ + if (s->output_ports.size() > 0 && s->output_ports.count(port_no) > 0) { + s->packet_counting_tree->dequeue_packet(packet_size, port_no, vc_no, term_id, app_id); + cc_router_congestion_check(s, lp, port_no, vc_no, rc_msg); + } +} + +void cc_router_forwarded_packet_rc(rlc_state *s, tw_lp *lp, unsigned int packet_size, int port_no, int vc_no, int term_id, int app_id, congestion_control_message *rc_msg) +{ + if (s->output_ports.size() > 0 && s->output_ports.count(port_no) > 0) { + cc_router_congestion_check_rc(s, lp, port_no, vc_no, rc_msg); + s->packet_counting_tree->enqueue_packet(packet_size, port_no, vc_no, term_id, app_id); + } +} + +void cc_router_congestion_check(rlc_state *s, tw_lp *lp, int port_no, int vc_no, congestion_control_message *rc_msg) +{ + int num_rngs = 0; + //PORT CONGESTION/DECONGESTION + int port_size = s->router_vc_sizes_on_each_port[port_no]*s->params->router_vc_per_port; + int port_congestion_threshold_size = s->params->single_port_congestion_threshold * port_size; + int port_decongestion_threshold_size = s->params->single_port_decongestion_threshold * port_size; + + unsigned long long port_occupancy = s->packet_counting_tree->get_packet_count_by_port(port_no); + rc_msg->size_abated = 0; + + //have we already registered congestion on this port? + if(s->packet_counting_tree->is_port_congested(port_no) == false) + { + if (port_occupancy >= port_congestion_threshold_size) { + s->packet_counting_tree->set_port_congestion_state(port_no, true); + + tw_stime expiration_delay = 2*bytes_to_ns(port_congestion_threshold_size-port_decongestion_threshold_size, s->router_bandwidths_on_each_port[port_no]); + // expiration_delay = max(expiration_delay, s->params->minimum_abatement_time); + s->packet_counting_tree->set_next_possible_port_normal_time(port_no, tw_now(lp)+expiration_delay); + + rc_msg->to_congest = 1; + // printf("CONGESTION DETECTED %llu\n", port_occupancy); + set< pair > aggressor_term_ids; + + map app_map = s->packet_counting_tree->get_app_count_map_by_port(port_no); + map::iterator it = app_map.begin(); + for (; it != app_map.end(); it++) + { + if ((it->second / port_occupancy) >= s->params->single_port_aggressor_usage_threshold) + { + map tcm = s->packet_counting_tree->get_term_count_map_by_port_from_app(port_no, it->first); + map::iterator agg_it = tcm.begin(); + for (; agg_it != tcm.end(); agg_it++) + { + aggressor_term_ids.insert( make_pair(agg_it->first, it->first) ); + } + } + } + + //create a store for the list of terms getting a mark of abatement + rc_msg->size_abated = aggressor_term_ids.size(); + rc_msg->danger_rc_abated = (unsigned int*)malloc(sizeof(unsigned int)*rc_msg->size_abated); + // printf("size abated %d\n", rc_msg->size_abated); + int stored = 0; + + //send an abatement signal to each aggressor terminal on this port if they aren't already abated + set< pair >::iterator set_it = aggressor_term_ids.begin(); + for(; set_it != aggressor_term_ids.end(); set_it++) + { + unsigned int term_id = set_it->first; + unsigned int app_id = set_it->second; + + //store into the rc storage + rc_msg->danger_rc_abated[stored] = term_id; + stored++; + + //check if its abated already, then mark the additional abatement + if (s->packet_counting_tree->is_abated_terminal(term_id) == 0) + { + tw_lpid term_lpgid = codes_mapping_get_lpid_from_relative(term_id, NULL, terminal_lp_name, NULL, 0); + congestion_control_message *c_msg; + tw_event *e = model_net_method_congestion_event(term_lpgid, s->params->notification_latency, s->lp, (void**)&c_msg, NULL); + c_msg->type = CC_SIGNAL_ABATE; + c_msg->app_id = app_id; + tw_event_send(e); + } + s->packet_counting_tree->mark_abated_terminal(port_no, term_id); //increments the abatement counter + } + } + } + else + { + if (tw_now(lp) > s->packet_counting_tree->get_next_possible_port_normal_time(port_no)) { + if (port_occupancy < port_decongestion_threshold_size) { + ///decongestion on this port! + rc_msg->to_decongest = 1; + s->packet_counting_tree->set_port_congestion_state(port_no, false); + // printf("Want to send Normal\n"); + + //get the terminals abated by this port + set abated_terms = s->packet_counting_tree->get_abated_terminals(port_no); + set::iterator it = abated_terms.begin(); + + //store the list of terms receiving a removal of a mark of abatement + rc_msg->size_deabated = abated_terms.size(); + rc_msg->danger_rc_deabated = (unsigned int*)malloc(sizeof(unsigned int)*rc_msg->size_deabated); + // printf("size deabated %d\n", rc_msg->size_deabated); + int stored = 0; + + for(; it != abated_terms.end(); it++) + { + rc_msg->danger_rc_deabated[stored] = *it; + stored++; + + //mark them unabated on this port + s->packet_counting_tree->mark_unabated_terminal(port_no, *it); + if (s->packet_counting_tree->is_abated_terminal(*it) == 0) + { + // printf("Sending Normal\n"); + //if any are no longer marked abated at all, then send a normal signal + tw_lpid term_lpgid = codes_mapping_get_lpid_from_relative(*it, NULL, terminal_lp_name, NULL, 0); + congestion_control_message *c_msg; + tw_event *e = model_net_method_congestion_event(term_lpgid, s->params->notification_latency, s->lp, (void**)&c_msg, NULL); + c_msg->type = CC_SIGNAL_NORMAL; + tw_event_send(e); + } + } + } + } + + // //check if any terminals have left the port entirely + // set abated_terms = s->packet_counting_tree->get_abated_terminals(port_no); + // set::iterator it = abated_terms.begin(); + // for(; it != abated_terms.end(); it++) + // { + // if (s->packet_counting_tree->get_packet_count_by_port_from_term(port_no, *it) == 0) + // { + // //mark them unabated on this port + // s->packet_counting_tree->mark_unabated_terminal(port_no, *it); + // if (s->packet_counting_tree->is_abated_terminal(*it) == false) + // { + // //if any are no longer marked abated at all, then send a normal signal + // tw_lpid term_lpgid = codes_mapping_get_lpid_from_relative(*it, NULL, terminal_lp_name, NULL, 0); + // congestion_control_message *c_msg; + // tw_event *e = model_net_method_congestion_event(term_lpgid, .1, s->lp, (void**)&c_msg, NULL); + // c_msg->type = CC_SIGNAL_NORMAL; + // tw_event_send(e); + // } + // } + // } + } + //other congestion checks would go here +} + +void cc_router_congestion_check_rc(rlc_state *s, tw_lp *lp, int port_no, int vc_no, congestion_control_message *rc_msg) +{ + if (rc_msg->to_congest) + { + //used danger_rc_abated to store size_abated unsigned int for terminal IDs + for (int i = 0; i < rc_msg->size_abated; i++) + { + s->packet_counting_tree->mark_unabated_terminal(port_no, rc_msg->danger_rc_abated[i]); + } + s->packet_counting_tree->set_port_congestion_state(port_no, false); + } + if (rc_msg->to_decongest) + { + //used danger_rc_deabated to store size_deabated unsigned ints for terminal IDs + for (int i = 0; i < rc_msg->size_deabated; i++) + { + s->packet_counting_tree->mark_abated_terminal(port_no, rc_msg->danger_rc_deabated[i]); + } + s->packet_counting_tree->set_port_congestion_state(port_no, true); + } + + // for(int i = 0; i < rc_msg->num_cc_rngs; i++) + // { + // cc_tw_rand_reverse_unif(s->lp); + // } +} + +void cc_router_local_controller_finalize(rlc_state *s) +{ + delete s->packet_counting_tree; +} + +static double calculate_bandwidth_usage_percent(int bytes_transmitted, double max_configured_bandwidth, int multiplier) +{ + double max_bw = max_configured_bandwidth* 1024.0 * 1024.0 * 1024.0; + double max_bw_per_ns = max_bw / (1000.0 * 1000.0 * 1000.0); + double max_bytes_per_win = max_bw_per_ns * cc_bandwidth_monitoring_window; + double percent_bw = (bytes_transmitted/ max_bytes_per_win); + // printf("%.2f percent bw\n", percent_bw); + + return percent_bw; +} + +void cc_terminal_process_bandwidth_check(tlc_state *s, congestion_control_message *msg, tw_lp *lp) +{ + double usage_percent = calculate_bandwidth_usage_percent(s->ejected_packet_bytes, s->params->terminal_configured_bandwidth, 1); //multiplier for multiple rails but right now we're just using 1 + double removed_window = s->ejected_rate_windows[s->window_epoch % cc_bandwidth_rolling_window_count]; + msg->saved_window = removed_window; + s->ejected_rate_windows[s->window_epoch % cc_bandwidth_rolling_window_count] = usage_percent; + + msg->saved_rate = s->cur_average_rate; + s->cur_average_rate = s->cur_average_rate * cc_bandwidth_rolling_window_count; + s->cur_average_rate = (s->cur_average_rate - removed_window + usage_percent)/cc_bandwidth_rolling_window_count; + if (s->cur_average_rate < 0) + s->cur_average_rate = 0; + + msg->saved_bw = s->current_injection_bandwidth_coef; + s->current_injection_bandwidth_coef = s->cur_average_rate; + if (s->is_abatement_active) + msg->saved_new_bw = s->current_injection_bandwidth_coef; //for commit m processing + else + msg->saved_new_bw = 1.0; + msg->msg_time = tw_now(lp); + + msg->saved_ejected_bytes = s->ejected_packet_bytes; + s->ejected_packet_bytes = 0; + s->window_epoch++; + + //schedule for the next heartbeat message if there's still workloads left + if (*s->workloads_finished_flag_ptr == 0) { + congestion_control_message *hb_msg; + tw_event * hb_e = model_net_method_congestion_event(s->lp->gid, cc_bandwidth_monitoring_window, s->lp, (void**)&hb_msg, NULL); + hb_msg->type = CC_BANDWIDTH_CHECK; + tw_event_send(hb_e); + } +} + +void cc_terminal_process_bandwidth_check_rc(tlc_state *s, congestion_control_message *msg, tw_lp *lp) +{ + s->window_epoch--; + s->ejected_packet_bytes = msg->saved_ejected_bytes; + s->current_injection_bandwidth_coef = msg->saved_bw; + s->cur_average_rate = msg->saved_rate; + s->ejected_rate_windows[s->window_epoch % cc_bandwidth_rolling_window_count] = msg->saved_window; +} + +void cc_terminal_local_controller_init(tlc_state *s, tw_lp *lp, int terminal_id, int* workload_finished_flag_ptr) +{ + s->params = (cc_param*)calloc(1, sizeof(cc_param)); + cc_param *p = s->params; + s->lp = lp; + s->terminal_id = terminal_id; + + //below is a brute force way to figure out what application a terminal is serving + // codes_mapping_get_lp_info(lp->gid, lp_group_name, &mapping_grp_id, NULL, + // &mapping_type_id, NULL, &mapping_rep_id, &mapping_offset); + + // struct codes_jobmap_ctx* ctx = congestion_control_get_jobmap(); + // char workload_lp_name[MAX_NAME_LENGTH]; + // workload_lp_name[0] = '\0'; + // configuration_get_value(&config, "PARAMS", "cc_workload_lpname", NULL, workload_lp_name, MAX_NAME_LENGTH); + // if (strlen(workload_lp_name) <= 0) { + // strcpy(workload_lp_name, "nw-lp"); //default workload LP name + // } + // int num_workload_lps = codes_mapping_get_lp_count(lp_group_name, 0, workload_lp_name, NULL, 0); + + // for (int work_rel_id = 0; work_rel_id < num_workload_lps; work_rel_id++) { + // tw_lpid work_gid = codes_mapping_get_lpid_from_relative(work_rel_id, NULL, workload_lp_name, NULL, 0); + // struct codes_jobmap_id job_ident = codes_jobmap_to_local_id(work_rel_id, ctx); //work rel id is job global id - TODO DOUBLE CHECK + // tw_lpid attached_term_id = model_net_find_local_device(DRAGONFLY_DALLY, NULL, 0, work_gid); + + // if (attached_term_id == lp->gid && job_ident.job != -1) { + // s->app_id = job_ident.job; //right now there's only one app per terminal, this may change in the future + // // s->workload_lpid_to_app_id[work_gid] = job_ident.job; + // // s->app_ids.insert(job_ident.job); + // } + // } + + int rc = configuration_get_value_double(&config, "PARAMS", "cn_bandwidth", NULL, &p->terminal_configured_bandwidth); + if(rc) { + if(!g_tw_mynode) + tw_error(TW_LOC, "Bandwidth of terminal links not specified."); + } + + rc = configuration_get_value_int(&config, "PARAMS", "chunk_size", NULL, &p->chunk_size); + if(rc) { + if(!g_tw_mynode) + tw_error(TW_LOC, "Chunk size not specified."); + } + + rc = configuration_get_value_double(&config, "PARAMS", "cc_measurement_period", NULL, &cc_bandwidth_monitoring_window); + if (rc) { + cc_bandwidth_monitoring_window = 10000; + } + + p->notification_latency = g_congestion_control_notif_latency; + + s->is_abatement_active = false; + s->current_injection_bandwidth_coef = 1; + s->abatement_signal_count = 0; + s->ejected_rate_windows = (double*)calloc(cc_bandwidth_rolling_window_count, sizeof(double)); + + s->workloads_finished_flag_ptr = workload_finished_flag_ptr; + + congestion_control_message *hb_msg; + tw_event * hb_e = model_net_method_congestion_event(lp->gid, cc_bandwidth_monitoring_window, s->lp, (void**)&hb_msg, NULL); + hb_msg->type = CC_BANDWIDTH_CHECK; + tw_event_send(hb_e); +} + +void cc_terminal_send_ack(tlc_state *s, tw_lpid original_terminal_lpgid) +{ + congestion_control_message *ack_msg; + tw_event * ack_e = model_net_method_congestion_event(original_terminal_lpgid, s->params->notification_latency + .00001, s->lp, (void**)&ack_msg, NULL); + ack_msg->type = CC_SIM_ACK; + tw_event_send(ack_e); +} + +void cc_terminal_send_ack_rc(tlc_state *s) +{ + // cc_tw_rand_reverse_unif(s->lp); +} + +void cc_terminal_receive_ack(tlc_state *s) +{ + s->ejected_packet_bytes += s->params->chunk_size; +} + +void cc_terminal_receive_ack_rc(tlc_state *s) +{ + s->ejected_packet_bytes -= s->params->chunk_size; +} + +void cc_terminal_start_abatement(tlc_state *s, congestion_control_message *msg) +{ + s->is_abatement_active = true; + msg->saved_bw = s->current_injection_bandwidth_coef; + s->current_injection_bandwidth_coef = s->cur_average_rate; + if (s->current_injection_bandwidth_coef < .01) + s->current_injection_bandwidth_coef = .01; + // printf("%d from app%d: Abating at %.2f\n", s->terminal_id, app_id, s->current_injection_bandwidth_coef); +} + +void cc_terminal_start_abatement_rc(tlc_state *s, congestion_control_message *msg) +{ + s->current_injection_bandwidth_coef = msg->saved_bw; + s->is_abatement_active = false; +} + +void cc_terminal_end_abatement(tlc_state *s, congestion_control_message *msg) +{ + s->is_abatement_active = false; + msg->saved_bw = s->current_injection_bandwidth_coef; + s->current_injection_bandwidth_coef = 1; + // printf("Returning to normal\n"); +} + +void cc_terminal_end_abatement_rc(tlc_state *s, congestion_control_message *msg) +{ + s->current_injection_bandwidth_coef = msg->saved_bw; + s->is_abatement_active = true; +} + +void cc_terminal_receive_abatement_signal(tlc_state *s, congestion_control_message *msg) +{ + s->abatement_signal_count++; + if (s->abatement_signal_count == 1) //if > 1, then it's already started + cc_terminal_start_abatement(s, msg); +} + +void cc_terminal_receive_abatement_signal_rc(tlc_state *s, congestion_control_message *msg) +{ + s->abatement_signal_count--; + if (s->abatement_signal_count == 0) + cc_terminal_start_abatement_rc(s, msg); +} + +void cc_terminal_receive_normal_signal(tlc_state *s, congestion_control_message *msg) +{ + s->abatement_signal_count--; + if (s->abatement_signal_count == 0) + cc_terminal_end_abatement(s, msg); +} + +void cc_terminal_receive_normal_signal_rc(tlc_state *s, congestion_control_message *msg) +{ + s->abatement_signal_count++; + if (s->abatement_signal_count == 1) + cc_terminal_end_abatement_rc(s, msg); +} + +double cc_terminal_get_current_injection_bandwidth_coef(tlc_state *s) +{ + if (!s->is_abatement_active) + return 1; + else if (s->abatement_signal_count > 0) { + double ret_val; + double calculated_injection = s->current_injection_bandwidth_coef; + // double min_injection = (1.0/codes_jobmap_get_num_ranks(s->app_id, jobmap_ctx)); //TODO s->app_id is never set because it's hard for the network side to know this + double min_injection = (1.0/100.0); + if (calculated_injection < min_injection) + ret_val = min_injection; + else + ret_val = calculated_injection; + + if (ret_val < 0) + printf("%.2f = %.2f / %d\n", ret_val, s->current_injection_bandwidth_coef, s->abatement_signal_count); + if (ret_val > 1) + ret_val = 1; + assert(ret_val <= 1); + assert(ret_val > 0); + return ret_val; + } + else { + tw_error(TW_LOC, "Abatement inactive but signal count > 0\n"); + return 1.0; + } +} + +bool cc_terminal_is_abatement_active(tlc_state *s) +{ + return s->is_abatement_active; +} + + +void cc_terminal_local_congestion_event(tlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + switch(msg->type) + { + case CC_SIGNAL_ABATE: + cc_terminal_receive_abatement_signal(s, msg); + break; + case CC_SIGNAL_NORMAL: + cc_terminal_receive_normal_signal(s, msg); + break; + case CC_BANDWIDTH_CHECK: + cc_terminal_process_bandwidth_check(s, msg, lp); + break; + case CC_SIM_ACK: + cc_terminal_receive_ack(s); + break; + default: + tw_error(TW_LOC, "Invalid event at cc terminal local congestion event"); + break; + } +} + +void cc_terminal_local_congestion_event_rc(tlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + switch(msg->type) + { + case CC_SIGNAL_ABATE: + cc_terminal_receive_abatement_signal_rc(s, msg); + break; + case CC_SIGNAL_NORMAL: + cc_terminal_receive_normal_signal_rc(s, msg); + break; + case CC_BANDWIDTH_CHECK: + cc_terminal_process_bandwidth_check_rc(s, msg, lp); + break; + case CC_SIM_ACK: + cc_terminal_receive_ack_rc(s); + break; + default: + tw_error(TW_LOC, "Invalid event at cc terminal local congestion event"); + break; + } +} + +void cc_terminal_local_congestion_event_commit(tlc_state *s, tw_bf *bf, congestion_control_message *msg, tw_lp *lp) +{ + switch(msg->type) + { + case CC_BANDWIDTH_CHECK: + if (OUTPUT_BANDWIDTHS) { + int written1; + char bandwidth_filename[128]; + written1 = sprintf(bandwidth_filename, "congestion-control-bandwidths"); + bandwidth_filename[written1] = '\0'; + + char tag_line[32]; + int written; + written = sprintf(tag_line, "%d %.2f %.5f\n",s->terminal_id, msg->saved_new_bw, msg->msg_time); + lp_io_write(lp->gid, bandwidth_filename, written, tag_line); + } + break; + case CC_SIGNAL_ABATE: + break; + case CC_SIGNAL_NORMAL: + break; + case CC_SIM_ACK: + break; + default: + tw_error(TW_LOC, "Invalid event at cc terminal local congestion event commit"); + break; + } +} \ No newline at end of file diff --git a/src/util/connection-manager.C b/src/util/connection-manager.C deleted file mode 100644 index eeaa7152..00000000 --- a/src/util/connection-manager.C +++ /dev/null @@ -1,344 +0,0 @@ -#include "codes/connection-manager.h" - - -//******************* 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; -} - -void ConnectionManager::add_connection(int dest_gid, ConnectionType type) -{ - Connection conn; - conn.src_lid = _source_id_local; - conn.src_gid = _source_id_global; - conn.src_group_id = _source_group; - conn.conn_type = type; - conn.dest_lid = dest_gid % _num_routers_per_group; - conn.dest_gid = dest_gid; - conn.dest_group_id = dest_gid / _num_routers_per_group; - - switch (type) - { - case CONN_LOCAL: - 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); - break; - - case CONN_GLOBAL: - 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); - break; - - case CONN_TERMINAL: - 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); - break; - - default: - assert(false); - // TW_ERROR(TW_LOC, "add_connection(dest_id, type): Undefined connection type\n"); - } - - if(conn.dest_group_id != conn.src_group_id) - _other_groups_i_connect_to_set.insert(conn.dest_group_id); - - _portMap[conn.port] = conn; -} - -// 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; -// } - -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 ConnectionManager::get_ports(int dest_id, ConnectionType type) -{ - vector< Connection > conns = this->get_connections_to_gid(dest_id, type); - - 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"); - } -} - -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) -{ - switch (type) - { - case CONN_LOCAL: - return intraGroupConnections[dest_gid%_num_routers_per_group]; - case CONN_GLOBAL: - return globalConnections[dest_gid]; - case CONN_TERMINAL: - return terminalConnections[dest_gid]; - default: - assert(false); - // TW_ERROR(TW_LOC, "get_connections(type): Undefined connection type\n"); - } -} - -vector< Connection > ConnectionManager::get_connections_to_group(int dest_group_id) -{ - return _connections_to_groups_map[dest_group_id]; -} - -vector< Connection > ConnectionManager::get_connections_by_type(ConnectionType type) -{ - switch (type) - { - 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"); - } -} - -vector< int > ConnectionManager::get_connected_group_ids() -{ - return _other_groups_i_connect_to; -} - -void ConnectionManager::solidify_connections() -{ - //-- other groups connect to - set< int >::iterator it; - for(it = _other_groups_i_connect_to_set.begin(); it != _other_groups_i_connect_to_set.end(); it++) - { - _other_groups_i_connect_to.push_back(*it); - } - - //--connections to group - 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; - } - - //--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; - } -} - - -void ConnectionManager::print_connections() -{ - printf("Connections for Router: %d ---------------------------------------\n",_source_id_global); - - int ports_printed = 0; - map::iterator it = _portMap.begin(); - for(; it != _portMap.end(); it++) - { - if ( (ports_printed == 0) && (_used_intra_ports > 0) ) - { - printf(" -- Intra-Group Connections -- \n"); - printf(" Port | Dest_ID | Group\n"); - } - if ( (ports_printed == _used_intra_ports) && (_used_inter_ports > 0) ) - { - printf(" -- Inter-Group Connections -- \n"); - printf(" Port | Dest_ID | Group\n"); - } - if ( (ports_printed == _used_intra_ports + _used_inter_ports) && (_used_terminal_ports > 0) ) - { - printf(" -- Terminal Connections -- \n"); - printf(" Port | Dest_ID | Group\n"); - } - - 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 - LOCAL\n", port_num, id, gid, group_id); - - } - 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); - } - else if (get_port_type(port_num) == CONN_TERMINAL) { - id = it->second.dest_gid; - printf(" %d -> %d : %d - TERMINAL\n", port_num, id, group_id); - } - - ports_printed++; - } -} diff --git a/src/util/rc-stack.c b/src/util/rc-stack.c index 612b271b..8df52463 100644 --- a/src/util/rc-stack.c +++ b/src/util/rc-stack.c @@ -16,7 +16,7 @@ enum rc_stack_mode { }; typedef struct rc_entry_s { - tw_stime time; + tw_event_sig e_sig; // ROSS 2D event timestamp (.recv_ts & .event_tiebreaker) void * data; void (*free_fn)(void*); struct qlist_head ql; @@ -63,7 +63,7 @@ void rc_stack_push( if (s->mode != RC_NONOPT || free_fn == NULL) { rc_entry * ent = (rc_entry*)malloc(sizeof(*ent)); assert(ent); - ent->time = tw_now(lp); + ent->e_sig = tw_now_sig(lp); ent->data = data; ent->free_fn = free_fn; qlist_add_tail(&ent->ql, &s->head); @@ -98,7 +98,11 @@ void rc_stack_gc(tw_lp const *lp, struct rc_stack *s) { struct qlist_head *ent = s->head.next; while (ent != &s->head) { rc_entry *r = qlist_entry(ent, rc_entry, ql); +#ifdef USE_RAND_TIEBREAKER + if (lp == NULL || tw_event_sig_compare(r->e_sig, lp->pe->GVT_sig) == -1) { +#else if (lp == NULL || r->time < lp->pe->GVT){ +#endif qlist_del(ent); if (r->free_fn) r->free_fn(r->data); free(r); diff --git a/src/workload/codes-workload.c b/src/workload/codes-workload.c index 190993d3..91cd49d4 100644 --- a/src/workload/codes-workload.c +++ b/src/workload/codes-workload.c @@ -9,6 +9,7 @@ #include #include #include +#include "codes_config.h" /* list of available methods. These are statically compiled for now, but we * could make generators optional via autoconf tests etc. if needed diff --git a/src/workload/methods/codes-online-comm-wrkld.C b/src/workload/methods/codes-online-comm-wrkld.C index 1ded7a92..c9e87406 100644 --- a/src/workload/methods/codes-online-comm-wrkld.C +++ b/src/workload/methods/codes-online-comm-wrkld.C @@ -24,6 +24,13 @@ #include "nekbone_swm_user_code.h" #include "nearest_neighbor_swm_user_code.h" #include "all_to_one_swm_user_code.h" +#include "one_to_many_swm_user_code.h" +#include "many_to_many_swm_user_code.h" +#include "milc_swm_user_code.h" +#include "allreduce.h" +#include "periodic_aggressor.h" +// #include "abt.h" +#include "layered_allbroadcast.h" #define ALLREDUCE_SHORT_MSG_SIZE 2048 @@ -428,6 +435,15 @@ void SWM_Sendrecv( SWM_ROUTING_TYPE reqrt, SWM_ROUTING_TYPE rsprt) { + +#if 1 +// Alternate, simpler implementation. Matches MPICH design. OpenMPI does Irecv+Send which also works. + uint32_t handle; + SWM_Irecv(recvpeer, comm_id, recvtag, recvbuf, &handle); + // SWM_Isend(sendpeer, comm_id, sendtag, sendreqvc, sendrspvc, sendbuf, sendbytes, pktrspbytes, &handles[0], reqrt, rsprt); + SWM_Send(sendpeer, comm_id, sendtag, sendreqvc, sendrspvc, sendbuf, sendbytes, pktrspbytes, reqrt, rsprt); + SWM_Wait(handle); +#else // printf("\n Sending to %d receiving from %d ", sendpeer, recvpeer); struct codes_workload_op send_op; @@ -473,6 +489,8 @@ void SWM_Sendrecv( ABT_thread_yield_to(global_prod_thread); num_sendrecv++; +#endif + } /* @param count: number of bytes in Allreduce @@ -747,6 +765,28 @@ void SWM_Finalize() ABT_thread_yield_to(global_prod_thread); } +void SWM_Mark_Iteration(SWM_TAG iter_tag) +{ + /* Add an event in the shared queue and then yield */ + struct codes_workload_op wrkld_per_rank; + + wrkld_per_rank.op_type = CODES_WK_MARK; + wrkld_per_rank.u.send.tag = iter_tag; + + /* Retreive the shared context state */ + ABT_thread prod; + void * arg; + int err = ABT_thread_self(&prod); + assert(err == ABT_SUCCESS); + err = ABT_thread_get_arg(prod, &arg); + assert(err == ABT_SUCCESS); + struct shared_context * sctx = static_cast(arg); + wrkld_per_rank.u.send.source_rank = sctx->my_rank; + sctx->fifo.push_back(&wrkld_per_rank); + + ABT_thread_yield_to(global_prod_thread); +} + static int hash_rank_compare(void *key, struct qhash_head *link) { rank_mpi_compare *in = (rank_mpi_compare*)key; @@ -761,12 +801,12 @@ static void workload_caller(void * arg) { shared_context* sctx = static_cast(arg); - if(strcmp(sctx->workload_name, "lammps") == 0) + if(strcmp(sctx->workload_name, "lammps") == 0 || strcmp(sctx->workload_name, "lammps1") == 0) { LAMMPS_SWM * lammps_swm = static_cast(sctx->swm_obj); lammps_swm->call(); } - else if(strcmp(sctx->workload_name, "nekbone") == 0) + else if(strcmp(sctx->workload_name, "nekbone") == 0 || strcmp(sctx->workload_name, "nekbone1") == 0) { NEKBONESWMUserCode * nekbone_swm = static_cast(sctx->swm_obj); nekbone_swm->call(); @@ -781,28 +821,40 @@ static void workload_caller(void * arg) AllToOneSWMUserCode * incast_swm = static_cast(sctx->swm_obj); incast_swm->call(); } + else if(strcmp(sctx->workload_name, "spread") == 0) + { + OneToManySWMUserCode * spread_swm = static_cast< OneToManySWMUserCode*>(sctx->swm_obj); + spread_swm->call(); + } + else if(strcmp(sctx->workload_name, "allreduce") == 0 || strcmp(sctx->workload_name, "allreduce32") == 0 || strcmp(sctx->workload_name, "allreduce256") == 0) + { + AllReduceSWMUserCode * allreduce_swm = static_cast< AllReduceSWMUserCode*>(sctx->swm_obj); + allreduce_swm->call(); + } + else if(strcmp(sctx->workload_name, "many_to_many") == 0 || strcmp(sctx->workload_name, "many_to_many1") == 0) + { + ManyToManySWMUserCode * many_to_many_swm = static_cast< ManyToManySWMUserCode*>(sctx->swm_obj); + many_to_many_swm->call(); + } + else if(strcmp(sctx->workload_name, "milc") == 0) + { + MilcSWMUserCode * milc_swm = static_cast< MilcSWMUserCode*>(sctx->swm_obj); + milc_swm->call(); + } + else if(strcmp(sctx->workload_name, "periodic_aggressor") == 0) + { + PeriodicAggressor * periodic_aggressor_swm = static_cast(sctx->swm_obj); + periodic_aggressor_swm->call(); + } + else if (strcmp(sctx->workload_name, "layered_allbcast") == 0) + { + LayeredAllBroadcast * layered_allbcast_swm = static_cast(sctx->swm_obj); + layered_allbcast_swm->call(); + } } -static int comm_online_workload_load(const char * params, int app_id, int rank) -{ - /* LOAD parameters from JSON file*/ - online_comm_params * o_params = (online_comm_params*)params; - int nprocs = o_params->nprocs; - - rank_mpi_context *my_ctx = new rank_mpi_context; - //my_ctx = (rank_mpi_context*)caloc(1, sizeof(rank_mpi_context)); - assert(my_ctx); - my_ctx->sctx.my_rank = rank; - my_ctx->sctx.num_ranks = nprocs; - my_ctx->sctx.wait_id = 0; - my_ctx->app_id = app_id; - void** generic_ptrs; - int array_len = 1; - generic_ptrs = (void**)calloc(array_len, sizeof(void*)); - generic_ptrs[0] = (void*)&rank; - - strcpy(my_ctx->sctx.workload_name, o_params->workload_name); - boost::property_tree::ptree root; +string get_default_path(online_comm_params * o_params) +{ string path; path.append(SWM_DATAROOTDIR); @@ -810,9 +862,17 @@ static int comm_online_workload_load(const char * params, int app_id, int rank) { path.append("/lammps_workload.json"); } + else if(strcmp(o_params->workload_name, "lammps1") == 0) + { + path.append("/lammps_workload1.json"); + } else if(strcmp(o_params->workload_name, "nekbone") == 0) { - path.append("/workload.json"); + path.append("/workload.json"); + } + else if(strcmp(o_params->workload_name, "nekbone1") == 0) + { + path.append("/workload1.json"); } else if(strcmp(o_params->workload_name, "nearest_neighbor") == 0) { @@ -830,26 +890,100 @@ static int comm_online_workload_load(const char * params, int app_id, int rank) { path.append("/incast2.json"); } + else if(strcmp(o_params->workload_name, "spread") == 0) + { + path.append("/spread_workload.json"); + } + else if(strcmp(o_params->workload_name, "allreduce") == 0) + { + path.append("/allreduce_workload.json"); + } + else if(strcmp(o_params->workload_name, "allreduce32") == 0) + { + path.append("/allreduce32_workload.json"); + } + else if(strcmp(o_params->workload_name, "allreduce256") == 0) + { + path.append("/allreduce256_workload.json"); + } + else if(strcmp(o_params->workload_name, "many_to_many") == 0) + { + path.append("/many_to_many_workload.json"); + } + else if(strcmp(o_params->workload_name, "many_to_many1") == 0) + { + path.append("/many_to_many_workload1.json"); + } + else if(strcmp(o_params->workload_name, "milc") == 0) + { + path.append("/milc_skeleton.json"); + } + else if(strcmp(o_params->workload_name, "periodic_aggressor") == 0) + { + path.append("/periodic_aggressor.json"); + } + else if (strcmp(o_params->workload_name, "layered_allbcast") == 0) + { + path.append("/layered_allbcast.json"); + } else tw_error(TW_LOC, "\n Undefined workload type %s ", o_params->workload_name); + return path; +} + + +static int comm_online_workload_load(const char * params, int app_id, int rank) +{ + /* LOAD parameters from JSON file*/ + online_comm_params * o_params = (online_comm_params*)params; + int nprocs = o_params->nprocs; + + rank_mpi_context *my_ctx = new rank_mpi_context; + //my_ctx = (rank_mpi_context*)caloc(1, sizeof(rank_mpi_context)); + assert(my_ctx); + my_ctx->sctx.my_rank = rank; + my_ctx->sctx.num_ranks = nprocs; + my_ctx->sctx.wait_id = 0; + my_ctx->app_id = app_id; + + void** generic_ptrs; + int array_len = 1; + generic_ptrs = (void**)calloc(array_len, sizeof(void*)); + generic_ptrs[0] = (void*)&rank; + + string path; + + if (o_params->workload_name[0] != '\0') { //then we were supplied with just the workload name, use default configs + strcpy(my_ctx->sctx.workload_name, o_params->workload_name); + path = get_default_path(o_params); + } + else { //then we were supplied a filepath to the config in the workload conf file + path = std::string(o_params->file_path); + } + + boost::property_tree::ptree root; try { std::ifstream jsonFile(path.c_str()); boost::property_tree::json_parser::read_json(jsonFile, root); uint32_t process_cnt = root.get("jobs.size", 1); - cpu_freq = root.get("jobs.cfg.cpu_freq") / 1e9; + cpu_freq = root.get("jobs.cfg.cpu_freq") / 1e9; + if (o_params->workload_name[0] == '\0') {//if we instead had a configuration filename supplied, get worklaod name from jobs.cfg.app + strcpy(o_params->workload_name, root.get("jobs.cfg.app").c_str()); + strcpy(my_ctx->sctx.workload_name, o_params->workload_name); + } } catch(std::exception & e) { printf("%s \n", e.what()); return -1; } - if(strcmp(o_params->workload_name, "lammps") == 0) + if(strcmp(o_params->workload_name, "lammps") == 0 || strcmp(o_params->workload_name, "lammps1") == 0) { LAMMPS_SWM * lammps_swm = new LAMMPS_SWM(root, generic_ptrs); my_ctx->sctx.swm_obj = (void*)lammps_swm; } - else if(strcmp(o_params->workload_name, "nekbone") == 0) + else if(strcmp(o_params->workload_name, "nekbone") == 0 || strcmp(o_params->workload_name, "nekbone1") == 0) { NEKBONESWMUserCode * nekbone_swm = new NEKBONESWMUserCode(root, generic_ptrs); my_ctx->sctx.swm_obj = (void*)nekbone_swm; @@ -864,6 +998,36 @@ static int comm_online_workload_load(const char * params, int app_id, int rank) AllToOneSWMUserCode * incast_swm = new AllToOneSWMUserCode(root, generic_ptrs); my_ctx->sctx.swm_obj = (void*)incast_swm; } + else if(strcmp(o_params->workload_name, "spread") == 0) + { + OneToManySWMUserCode * spread_swm = new OneToManySWMUserCode(root, generic_ptrs); + my_ctx->sctx.swm_obj = (void*)spread_swm; + } + else if(strcmp(o_params->workload_name, "allreduce") == 0 || strcmp(o_params->workload_name, "allreduce32") == 0 || strcmp(o_params->workload_name, "allreduce256") == 0) + { + AllReduceSWMUserCode * allreduce_swm = new AllReduceSWMUserCode(root, generic_ptrs); + my_ctx->sctx.swm_obj = (void*)allreduce_swm; + } + else if(strcmp(o_params->workload_name, "many_to_many") == 0 || strcmp(o_params->workload_name, "many_to_many1") == 0) + { + ManyToManySWMUserCode * many_to_many_swm = new ManyToManySWMUserCode(root, generic_ptrs); + my_ctx->sctx.swm_obj = (void*)many_to_many_swm; + } + else if(strcmp(o_params->workload_name, "milc") == 0) + { + MilcSWMUserCode * milc_swm = new MilcSWMUserCode(root, generic_ptrs); + my_ctx->sctx.swm_obj = (void*)milc_swm; + } + else if(strcmp(o_params->workload_name, "periodic_aggressor") == 0) + { + PeriodicAggressor * periodic_aggressor_swm = new PeriodicAggressor(root, generic_ptrs); + my_ctx->sctx.swm_obj = (void*)periodic_aggressor_swm; + } + else if (strcmp(o_params->workload_name, "layered_allbcast") == 0) + { + LayeredAllBroadcast * layered_allbcast_swm = new LayeredAllBroadcast(root, generic_ptrs); + my_ctx->sctx.swm_obj = (void*)layered_allbcast_swm; + } if(global_prod_thread == NULL) { diff --git a/tests/conf/modelnet-p2p-bw-loggp.conf b/tests/conf/modelnet-p2p-bw-loggp.conf index bedce682..93da757b 100644 --- a/tests/conf/modelnet-p2p-bw-loggp.conf +++ b/tests/conf/modelnet-p2p-bw-loggp.conf @@ -10,7 +10,7 @@ LPGROUPS PARAMS { packet_size="2147483648"; - message_size="368"; + message_size="384"; modelnet_order=( "loggp" ); # scheduler options modelnet_scheduler="fcfs"; diff --git a/tests/conf/modelnet-prio-sched-test.conf b/tests/conf/modelnet-prio-sched-test.conf index 82f996fd..b6cdd9b2 100644 --- a/tests/conf/modelnet-prio-sched-test.conf +++ b/tests/conf/modelnet-prio-sched-test.conf @@ -10,7 +10,7 @@ LPGROUPS PARAMS { packet_size="512"; - message_size="400"; + message_size="416"; modelnet_order=( "simplenet" ); # scheduler options modelnet_scheduler="priority"; diff --git a/tests/conf/modelnet-test-dragonfly.conf b/tests/conf/modelnet-test-dragonfly.conf index addce734..3c7e9a3b 100644 --- a/tests/conf/modelnet-test-dragonfly.conf +++ b/tests/conf/modelnet-test-dragonfly.conf @@ -23,6 +23,6 @@ PARAMS local_bandwidth="5.25"; global_bandwidth="4.7"; cn_bandwidth="5.25"; - message_size="384"; + message_size="400"; routing="nonminimal"; } diff --git a/tests/conf/modelnet-test-loggp.conf b/tests/conf/modelnet-test-loggp.conf index 1cf50d78..139641fb 100644 --- a/tests/conf/modelnet-test-loggp.conf +++ b/tests/conf/modelnet-test-loggp.conf @@ -9,7 +9,7 @@ LPGROUPS } PARAMS { - message_size="384"; + message_size="400"; modelnet_order=( "loggp" ); # scheduler options modelnet_scheduler="fcfs-full"; diff --git a/tests/conf/modelnet-test-slimfly.conf b/tests/conf/modelnet-test-slimfly.conf index 1af61e8d..7d01910b 100644 --- a/tests/conf/modelnet-test-slimfly.conf +++ b/tests/conf/modelnet-test-slimfly.conf @@ -30,6 +30,6 @@ PARAMS global_bandwidth="9.0"; cn_bandwidth="9.0"; link_delay = "0"; - message_size="384"; + message_size="400"; routing="minimal"; } diff --git a/tests/conf/modelnet-test-torus.conf b/tests/conf/modelnet-test-torus.conf index 864443e3..2d8d6cdf 100644 --- a/tests/conf/modelnet-test-torus.conf +++ b/tests/conf/modelnet-test-torus.conf @@ -14,7 +14,7 @@ PARAMS # scheduler options modelnet_scheduler="fcfs"; # modelnet_scheduler="round-robin"; - message_size="384"; + message_size="400"; n_dims="3"; dim_length="4,2,2"; link_bandwidth="2.0"; diff --git a/tests/conf/modelnet-test.conf b/tests/conf/modelnet-test.conf index 6b7bbc5f..938b9fe2 100644 --- a/tests/conf/modelnet-test.conf +++ b/tests/conf/modelnet-test.conf @@ -10,7 +10,7 @@ LPGROUPS PARAMS { packet_size="512"; - message_size="384"; + message_size="400"; modelnet_order=( "simplenet" ); # scheduler options modelnet_scheduler="fcfs"; diff --git a/tests/rc-stack-test.c b/tests/rc-stack-test.c index 69017abf..06231f60 100644 --- a/tests/rc-stack-test.c +++ b/tests/rc-stack-test.c @@ -38,6 +38,18 @@ int main() *c = 3; \ } while (0) + +#ifdef USE_RAND_TIEBREAKER +#define PUSH_ALL() \ + do { \ + kp.last_sig.recv_ts = 1.0; \ + rc_stack_push(&lp, a, free, s); \ + kp.last_sig.recv_ts = 2.0; \ + rc_stack_push(&lp, b, free, s); \ + kp.last_sig.recv_ts = 3.0; \ + rc_stack_push(&lp, c, free, s); \ + } while (0) +#else #define PUSH_ALL() \ do { \ kp.last_time = 1.0; \ @@ -47,6 +59,7 @@ int main() kp.last_time = 3.0; \ rc_stack_push(&lp, c, free, s); \ } while (0) +#endif ALLOC_ALL(); PUSH_ALL(); @@ -62,8 +75,14 @@ int main() assert(0 == rc_stack_count(s)); PUSH_ALL(); + +#ifdef USE_RAND_TIEBREAKER + /* garbage collect the first two (NOT freeing the pointers first) */ + pe.GVT_sig.recv_ts = 2.5; +#else /* garbage collect the first two (NOT freeing the pointers first) */ pe.GVT = 2.5; +#endif rc_stack_gc(&lp, s); assert(1 == rc_stack_count(s));