diff options
| author | Dongdong Li <[email protected]> | 2013-08-08 00:15:58 -0800 |
|---|---|---|
| committer | Andrew Boktor <[email protected]> | 2014-08-14 13:50:58 -0700 |
| commit | 7f49fe9feb174d34efc2a011bad79b38522a360b (patch) | |
| tree | ab5b7b66e40315a81871acbf386722981020f866 | |
| parent | 5f91e7435742bab74dfbeca18afc63e466498f36 (diff) | |
Intesim2 Integration
Details: See Review 80001 https://gpgpu-sim-code-review.appspot.com/80001/
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 16747]
144 files changed, 27984 insertions, 118 deletions
@@ -49,6 +49,9 @@ Version 3.2.1+edits (development branch) versus 3.2.1 cache bank is configured to access at most 32B/cycle. With twice the number of connections to the memory partitions, the interconnection network now runs at half of its original speed. +- Replaced intersim with intersim2. intersim is the original BookSim with + extentions to interface with GPGPU-Sim. We applied similar changes to + BookSim 2.0. - Bug Fixes: - Fixed the flit count sent to GPUWattch for atomic operations. - Fix for Bug 51 - Updated the function declaration of @@ -29,6 +29,9 @@ # comment out next line to disable OpenGL support # export OPENGL_SUPPORT=1 +# (Temp) Using intersim2 by deafult, to use intersim, type make INTERSIM=intersim +INTERSIM ?= intersim2 + include version_detection.mk ifeq ($(GPGPUSIM_CONFIG), gcc-$(CC_VERSION)/cuda-$(CUDART_VERSION)/debug) @@ -51,7 +54,7 @@ ifneq ($(shell which nvcc), "") endif endif -LIBS = cuda-sim gpgpu-sim_uarch intersim gpgpusimlib +LIBS = cuda-sim gpgpu-sim_uarch $(INTERSIM) gpgpusimlib TARGETS = @@ -142,7 +145,7 @@ $(SIM_LIB_DIR)/libcudart.so: makedirs $(LIBS) cudalib $(SIM_OBJ_FILES_DIR)/cuda-sim/*.o \ $(SIM_OBJ_FILES_DIR)/cuda-sim/decuda_pred_table/*.o \ $(SIM_OBJ_FILES_DIR)/gpgpu-sim/*.o \ - $(SIM_OBJ_FILES_DIR)/intersim/*.o \ + $(SIM_OBJ_FILES_DIR)/$(INTERSIM)/*.o \ $(SIM_OBJ_FILES_DIR)/*.o -lm -lz -lGL -pthread \ $(MCPAT) \ -o $(SIM_LIB_DIR)/libcudart.so @@ -156,7 +159,7 @@ $(SIM_LIB_DIR)/libcudart.dylib: makedirs $(LIBS) cudalib $(SIM_OBJ_FILES_DIR)/cuda-sim/*.o \ $(SIM_OBJ_FILES_DIR)/cuda-sim/decuda_pred_table/*.o \ $(SIM_OBJ_FILES_DIR)/gpgpu-sim/*.o \ - $(SIM_OBJ_FILES_DIR)/intersim/*.o \ + $(SIM_OBJ_FILES_DIR)/$(INTERSIM)/*.o \ $(SIM_OBJ_FILES_DIR)/*.o -lm -lz -pthread \ $(MCPAT) \ -o $(SIM_LIB_DIR)/libcudart.dylib @@ -167,7 +170,7 @@ $(SIM_LIB_DIR)/libOpenCL.so: makedirs $(LIBS) opencllib $(SIM_OBJ_FILES_DIR)/cuda-sim/*.o \ $(SIM_OBJ_FILES_DIR)/cuda-sim/decuda_pred_table/*.o \ $(SIM_OBJ_FILES_DIR)/gpgpu-sim/*.o \ - $(SIM_OBJ_FILES_DIR)/intersim/*.o \ + $(SIM_OBJ_FILES_DIR)/$(INTERSIM)/*.o \ $(SIM_OBJ_FILES_DIR)/*.o -lm -lz -lGL -pthread \ $(MCPAT) \ -o $(SIM_LIB_DIR)/libOpenCL.so @@ -192,10 +195,10 @@ gpgpu-sim_uarch: makedirs cuda-sim $(MAKE) -C ./src/gpgpu-sim/ depend $(MAKE) -C ./src/gpgpu-sim/ -intersim: makedirs cuda-sim gpgpu-sim_uarch - $(MAKE) "CREATELIBRARY=1" "DEBUG=$(DEBUG)" -C ./src/intersim +$(INTERSIM): makedirs cuda-sim gpgpu-sim_uarch + $(MAKE) "CREATE_LIBRARY=1" "DEBUG=$(DEBUG)" -C ./src/$(INTERSIM) -gpgpusimlib: makedirs cuda-sim gpgpu-sim_uarch intersim +gpgpusimlib: makedirs cuda-sim gpgpu-sim_uarch $(INTERSIM) $(MAKE) -C ./src/ depend $(MAKE) -C ./src/ @@ -216,7 +219,7 @@ makedirs: if [ ! -d $(SIM_OBJ_FILES_DIR)/gpgpu-sim ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/gpgpu-sim; fi; if [ ! -d $(SIM_OBJ_FILES_DIR)/libopencl ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/libopencl; fi; if [ ! -d $(SIM_OBJ_FILES_DIR)/libopencl/bin ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/libopencl/bin; fi; - if [ ! -d $(SIM_OBJ_FILES_DIR)/intersim ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/intersim; fi; + if [ ! -d $(SIM_OBJ_FILES_DIR)/$(INTERSIM) ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/$(INTERSIM); fi; if [ ! -d $(SIM_OBJ_FILES_DIR)/cuobjdump_to_ptxplus ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/cuobjdump_to_ptxplus; fi; if [ ! -d $(SIM_OBJ_FILES_DIR)/gpuwattch ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/gpuwattch; fi; if [ ! -d $(SIM_OBJ_FILES_DIR)/gpuwattch/cacti ]; then mkdir -p $(SIM_OBJ_FILES_DIR)/gpuwattch/cacti; fi; diff --git a/configs/GTX480/config_fermi_islip.icnt b/configs/GTX480/config_fermi_islip.icnt index 07a4b10..7820e4e 100644 --- a/configs/GTX480/config_fermi_islip.icnt +++ b/configs/GTX480/config_fermi_islip.icnt @@ -1,6 +1,8 @@ +//21*1 fly with 32 flits per packet under gpgpusim injection mode use_map = 0; flit_size = 32; +// currently we do not use this, see subnets below network_count = 2; // Topology @@ -9,41 +11,60 @@ k = 27; n = 1; // Routing -routing_function = dest_tag;//dim_order;//min_adapt;//dim_order;//_ni; + +routing_function = dest_tag; // Flow control -num_vcs = 1; //4; -vc_buf_size = 8; //16; + +num_vcs = 1; +vc_buf_size = 8; + wait_for_tail_credit = 0; // Router architecture -vc_allocator = islip;//i1_pim; //islip; //pim -sw_allocator = islip;//i1_pim;//islip; //pim +vc_allocator = islip; //separable_input_first; +sw_allocator = islip; //separable_input_first; alloc_iters = 1; credit_delay = 0; routing_delay = 0; -vc_alloc_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; input_speedup = 2; output_speedup = 1; internal_speedup = 1.0; -// Traffic (DO NOT CHANGE THIS) -traffic = gpgpusim; +// Traffic, GPGPU-Sim does not use this + +traffic = uniform; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; + +// Simulation - Don't change -//not used in gpgpusim -// const_flits_per_packet = 3; -injection_process = gpgpu_injector; -// Simulation -//not used in gpgpusim -sim_type = latency; +sim_type = gpgpusim; +//sim_type = latency; injection_rate = 0.1; +subnets = 2; + +// Always use read and write no matter following line +//use_read_write = 1; + + +read_request_subnet = 0; +read_reply_subnet = 1; +write_request_subnet = 0; +write_reply_subnet = 1; + +read_request_begin_vc = 0; +read_request_end_vc = 0; +write_request_begin_vc = 0; +write_request_end_vc = 0; +read_reply_begin_vc = 0; +read_reply_end_vc = 0; +write_reply_begin_vc = 0; +write_reply_end_vc = 0; -// Statistics for Interconnection (Added for GPGPU-Sim) -MATLAB_OUTPUT = 1; // output data in MATLAB friendly format -DISPLAY_LAT_DIST = 1; // distribution of packet latencies -DISPLAY_HOP_DIST = 1; // distribution of hop counts -DISPLAY_PAIR_LATENCY = 0; diff --git a/configs/QuadroFX5600/icnt_config_islip.icnt b/configs/QuadroFX5600/icnt_config_islip.icnt index b321d0a..de3bcc8 100644 --- a/configs/QuadroFX5600/icnt_config_islip.icnt +++ b/configs/QuadroFX5600/icnt_config_islip.icnt @@ -1,6 +1,8 @@ +//14*1 fly with 32 flits per packet under gpgpusim injection mode use_map = 0; flit_size = 32; +// currently we donot use this, see subnets below network_count = 2; // Topology @@ -9,41 +11,60 @@ k = 14; n = 1; // Routing -routing_function = dest_tag;//dim_order;//min_adapt;//dim_order;//_ni; + +routing_function = dest_tag; // Flow control -num_vcs = 1; //4; -vc_buf_size = 8; //16; + +num_vcs = 1; +vc_buf_size = 8; + wait_for_tail_credit = 0; // Router architecture -vc_allocator = islip;//i1_pim; //islip; //pim -sw_allocator = islip;//i1_pim;//islip; //pim +vc_allocator = islip; //separable_input_first; +sw_allocator = islip; //separable_input_first; alloc_iters = 1; credit_delay = 0; routing_delay = 0; -vc_alloc_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; input_speedup = 2; output_speedup = 1; internal_speedup = 1.0; -// Traffic (DO NOT CHANGE THIS) -traffic = gpgpusim; +// Traffic, GPGPU-Sim does not use this + +traffic = uniform; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; + +// Simulation - Don't change -//not used in gpgpusim -// const_flits_per_packet = 3; -injection_process = gpgpu_injector; -// Simulation -//not used in gpgpusim -sim_type = latency; +sim_type = gpgpusim; +//sim_type = latency; injection_rate = 0.1; +subnets = 2; + +// Always use read and write no matter following line +//use_read_write = 1; + + +read_request_subnet = 0; +read_reply_subnet = 1; +write_request_subnet = 0; +write_reply_subnet = 1; + +read_request_begin_vc = 0; +read_request_end_vc = 0; +write_request_begin_vc = 0; +write_request_end_vc = 0; +read_reply_begin_vc = 0; +read_reply_end_vc = 0; +write_reply_begin_vc = 0; +write_reply_end_vc = 0; -// Statistics for Interconnection (Added for GPGPU-Sim) -MATLAB_OUTPUT = 1; // output data in MATLAB friendly format -DISPLAY_LAT_DIST = 1; // distribution of packet latencies -DISPLAY_HOP_DIST = 1; // distribution of hop counts -DISPLAY_PAIR_LATENCY = 0; diff --git a/configs/QuadroFX5800/config_quadro_islip.icnt b/configs/QuadroFX5800/config_quadro_islip.icnt index be385a1..cfe9cac 100644 --- a/configs/QuadroFX5800/config_quadro_islip.icnt +++ b/configs/QuadroFX5800/config_quadro_islip.icnt @@ -1,6 +1,8 @@ +//18*1 fly with 32 flits per packet under gpgpusim injection mode use_map = 0; flit_size = 32; +// currently we donot use this, see subnets below network_count = 2; // Topology @@ -9,41 +11,59 @@ k = 18; n = 1; // Routing -routing_function = dest_tag;//dim_order;//min_adapt;//dim_order;//_ni; + +routing_function = dest_tag; // Flow control -num_vcs = 1; //4; -vc_buf_size = 8; //16; + +num_vcs = 1; +vc_buf_size = 8; + wait_for_tail_credit = 0; // Router architecture -vc_allocator = islip;//i1_pim; //islip; //pim -sw_allocator = islip;//i1_pim;//islip; //pim +vc_allocator = islip; //separable_input_first; +sw_allocator = islip; //separable_input_first; alloc_iters = 1; credit_delay = 0; routing_delay = 0; -vc_alloc_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; input_speedup = 2; output_speedup = 1; internal_speedup = 1.0; -// Traffic (DO NOT CHANGE THIS) -traffic = gpgpusim; +// Traffic, GPGPU-Sim does not use this +traffic = uniform; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; -//not used in gpgpusim -// const_flits_per_packet = 3; -injection_process = gpgpu_injector; -// Simulation -//not used in gpgpusim -sim_type = latency; +// Simulation - Don't change +sim_type = gpgpusim; +//sim_type = latency; injection_rate = 0.1; -// Statistics for Interconnection (Added for GPGPU-Sim) -MATLAB_OUTPUT = 1; // output data in MATLAB friendly format -DISPLAY_LAT_DIST = 1; // distribution of packet latencies -DISPLAY_HOP_DIST = 1; // distribution of hop counts -DISPLAY_PAIR_LATENCY = 0; +subnets = 2; + +// Always use read and write no matter following line +//use_read_write = 1; + + +read_request_subnet = 0; +read_reply_subnet = 1; +write_request_subnet = 0; +write_reply_subnet = 1; + +read_request_begin_vc = 0; +read_request_end_vc = 0; +write_request_begin_vc = 0; +write_request_end_vc = 0; +read_reply_begin_vc = 0; +read_reply_end_vc = 0; +write_reply_begin_vc = 0; +write_reply_end_vc = 0; + diff --git a/configs/TeslaC2050/config_fermi_islip.icnt b/configs/TeslaC2050/config_fermi_islip.icnt index c1a272c..a11bd8e 100644 --- a/configs/TeslaC2050/config_fermi_islip.icnt +++ b/configs/TeslaC2050/config_fermi_islip.icnt @@ -1,6 +1,8 @@ +//20*1 fly with 32 flits per packet under gpgpusim injection mode use_map = 0; flit_size = 32; +// currently we donot use this, see subnets below network_count = 2; // Topology @@ -9,41 +11,60 @@ k = 26; n = 1; // Routing -routing_function = dest_tag;//dim_order;//min_adapt;//dim_order;//_ni; + +routing_function = dest_tag; // Flow control -num_vcs = 1; //4; -vc_buf_size = 8; //16; + +num_vcs = 1; +vc_buf_size = 8; + wait_for_tail_credit = 0; // Router architecture -vc_allocator = islip;//i1_pim; //islip; //pim -sw_allocator = islip;//i1_pim;//islip; //pim +vc_allocator = islip; //separable_input_first; +sw_allocator = islip; //separable_input_first; alloc_iters = 1; credit_delay = 0; routing_delay = 0; -vc_alloc_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; input_speedup = 2; output_speedup = 1; internal_speedup = 1.0; -// Traffic (DO NOT CHANGE THIS) -traffic = gpgpusim; +// Traffic, GPGPU-Sim does not use this + +traffic = uniform; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; + +// Simulation - Don't change -//not used in gpgpusim -// const_flits_per_packet = 3; -injection_process = gpgpu_injector; -// Simulation -//not used in gpgpusim -sim_type = latency; +sim_type = gpgpusim; +//sim_type = latency; injection_rate = 0.1; -// Statistics for Interconnection (Added for GPGPU-Sim) -MATLAB_OUTPUT = 1; // output data in MATLAB friendly format -DISPLAY_LAT_DIST = 1; // distribution of packet latencies -DISPLAY_HOP_DIST = 1; // distribution of hop counts -DISPLAY_PAIR_LATENCY = 0; +subnets = 2; + +// Always use read and write no matter following line +//use_read_write = 1; + + +read_request_subnet = 0; +read_reply_subnet = 1; +write_request_subnet = 0; +write_reply_subnet = 1; + +read_request_begin_vc = 0; +read_request_end_vc = 0; +write_request_begin_vc = 0; +write_request_end_vc = 0; +read_reply_begin_vc = 0; +read_reply_end_vc = 0; +write_reply_begin_vc = 0; +write_reply_end_vc = 0; diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index ef50588..dd76e4b 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -35,7 +35,7 @@ #include <stdio.h> #include "opcodes.h" -#include "../intersim/statwraper.h" +#include "../statwrapper.h" #include <set> #include <map> #include "../abstract_hardware_model.h" diff --git a/src/gpgpu-sim/delayqueue.h b/src/gpgpu-sim/delayqueue.h index fd921bf..b25f143 100644 --- a/src/gpgpu-sim/delayqueue.h +++ b/src/gpgpu-sim/delayqueue.h @@ -32,7 +32,7 @@ #ifndef DELAYQUEUE_H #define DELAYQUEUE_H -#include "../intersim/statwraper.h" +#include "../statwrapper.h" #include "gpu-misc.h" template <class T> diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index 53d13fa..36e72e8 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -51,8 +51,7 @@ #include "l2cache.h" #include "../cuda-sim/ptx-stats.h" -#include "../intersim/statwraper.h" -#include "../intersim/interconnect_interface.h" +#include "../statwrapper.h" #include "../abstract_hardware_model.h" #include "../debug.h" #include "../gpgpusim_entrypoint.h" @@ -579,7 +578,7 @@ gpgpu_sim::gpgpu_sim( const gpgpu_sim_config &config ) } } - icnt_init(m_shader_config->n_simt_clusters,m_memory_config->m_n_mem_sub_partition); + icnt_wrapper_init(m_shader_config->n_simt_clusters,m_memory_config->m_n_mem_sub_partition); time_vector_create(NUM_MEM_REQ_STAT); fprintf(stdout, "GPGPU-Sim uArch: performance model initialization complete.\n"); @@ -702,8 +701,8 @@ void gpgpu_sim::init() set_spill_interval (m_config.gpgpu_cflog_interval * 40); } - if (g_network_mode) - icnt_init_grid(); + if (g_network_mode) + icnt_init(); // McPAT initialization function. Called on first launch of GPU #ifdef GPGPUSIM_POWER_MODEL @@ -721,15 +720,14 @@ void gpgpu_sim::update_stats() { void gpgpu_sim::print_stats() { - ptx_file_line_stats_write_file(); gpu_print_stat(); if (g_network_mode) { - interconnect_stats(); - printf("----------------------------Interconnect-DETAILS---------------------------------" ); - icnt_overal_stat(); - printf("----------------------------END-of-Interconnect-DETAILS-------------------------" ); + printf("----------------------------Interconnect-DETAILS--------------------------------\n" ); + icnt_display_stats(); + icnt_display_overall_stats(); + printf("----------------------------END-of-Interconnect-DETAILS-------------------------\n" ); } } @@ -765,7 +763,7 @@ void gpgpu_sim::deadlock_check() } if( icnt_busy() ) { printf("GPGPU-Sim uArch DEADLOCK: iterconnect contains traffic\n"); - display_icnt_state( stdout ); + icnt_display_state( stdout ); } printf("\nRe-run the simulator in gdb and use debug routines in .gdbinit to debug this\n"); fflush(stdout); diff --git a/src/gpgpu-sim/icnt_wrapper.cc b/src/gpgpu-sim/icnt_wrapper.cc index f8c981d..c005dd9 100644 --- a/src/gpgpu-sim/icnt_wrapper.cc +++ b/src/gpgpu-sim/icnt_wrapper.cc @@ -27,13 +27,18 @@ #include "icnt_wrapper.h" #include <assert.h> -#include "../intersim/interconnect_interface.h" +#include "../intersim2/globals.hpp" +#include "../intersim2/interconnect_interface.hpp" +icnt_init_p icnt_init; icnt_has_buffer_p icnt_has_buffer; icnt_push_p icnt_push; icnt_pop_p icnt_pop; icnt_transfer_p icnt_transfer; icnt_busy_p icnt_busy; +icnt_display_stats_p icnt_display_stats; +icnt_display_overall_stats_p icnt_display_overall_stats; +icnt_display_state_p icnt_display_state; icnt_get_flit_size_p icnt_get_flit_size; int g_network_mode; @@ -41,27 +46,83 @@ char* g_network_config_filename; #include "../option_parser.h" +// Wrapper to intersim2 to accompany old icnt_wrapper +// TODO: use delegate/boost/c++11<funtion> instead +static void intersim2_init() +{ + g_icnt_interface->Init(); +} + +static bool intersim2_has_buffer(unsigned input, unsigned int size) +{ + return g_icnt_interface->HasBuffer(input, size); +} + +static void intersim2_push(unsigned input, unsigned output, void* data, unsigned int size) +{ + g_icnt_interface->Push(input, output, data, size); +} + +static void* intersim2_pop(unsigned output) +{ + return g_icnt_interface->Pop(output); +} + +static void intersim2_transfer() +{ + g_icnt_interface->Advance(); +} + +static bool intersim2_busy() +{ + return g_icnt_interface->Busy(); +} + +static void intersim2_display_stats() +{ + g_icnt_interface->DisplayStats(); +} + +static void intersim2_display_overall_stats() +{ + g_icnt_interface->DisplayOverallStats(); +} + +static void intersim2_display_state(FILE *fp) +{ + g_icnt_interface->DisplayState(fp); +} + +static unsigned intersim2_get_flit_size() +{ + return g_icnt_interface->GetFlitSize(); +} + void icnt_reg_options( class OptionParser * opp ) { option_parser_register(opp, "-network_mode", OPT_INT32, &g_network_mode, "Interconnection network mode", "1"); option_parser_register(opp, "-inter_config_file", OPT_CSTR, &g_network_config_filename, "Interconnection network config file", "mesh"); } -void icnt_init( unsigned int n_shader, unsigned int n_mem ) +void icnt_wrapper_init( unsigned int n_shader, unsigned int n_mem ) { switch (g_network_mode) { - case INTERSIM: - init_interconnect(g_network_config_filename, n_shader, n_mem ); - icnt_has_buffer = interconnect_has_buffer; - icnt_push = interconnect_push; - icnt_pop = interconnect_pop; - icnt_transfer = advance_interconnect; - icnt_busy = interconnect_busy; - icnt_get_flit_size = interconnect_get_flit_size; - break; - - default: - assert(0); - break; + case INTERSIM: + //FIXME: delete the object: may add icnt_done wrapper + g_icnt_interface = new InterconnectInterface(g_network_config_filename, n_shader, n_mem ); + icnt_init = intersim2_init; + icnt_has_buffer = intersim2_has_buffer; + icnt_push = intersim2_push; + icnt_pop = intersim2_pop; + icnt_transfer = intersim2_transfer; + icnt_busy = intersim2_busy; + icnt_display_stats = intersim2_display_stats; + icnt_display_overall_stats = intersim2_display_overall_stats; + icnt_display_state = intersim2_display_state; + icnt_get_flit_size = intersim2_get_flit_size; + break; + default: + assert(0); + break; } } diff --git a/src/gpgpu-sim/icnt_wrapper.h b/src/gpgpu-sim/icnt_wrapper.h index f8e6baf..2cbe0df 100644 --- a/src/gpgpu-sim/icnt_wrapper.h +++ b/src/gpgpu-sim/icnt_wrapper.h @@ -31,21 +31,30 @@ #include <stdio.h> // functional interface to the interconnect + +typedef void (*icnt_init_p)( ); typedef bool (*icnt_has_buffer_p)(unsigned input, unsigned int size); typedef void (*icnt_push_p)(unsigned input, unsigned output, void* data, unsigned int size); typedef void* (*icnt_pop_p)(unsigned output); typedef void (*icnt_transfer_p)( ); -typedef unsigned (*icnt_busy_p)( ); +typedef bool (*icnt_busy_p)( ); typedef void (*icnt_drain_p)( ); +typedef void (*icnt_display_stats_p)( ); +typedef void (*icnt_display_overall_stats_p)( ); +typedef void (*icnt_display_state_p)(FILE* fp); typedef unsigned (*icnt_get_flit_size_p)(); +extern icnt_init_p icnt_init; extern icnt_has_buffer_p icnt_has_buffer; extern icnt_push_p icnt_push; extern icnt_pop_p icnt_pop; extern icnt_transfer_p icnt_transfer; extern icnt_busy_p icnt_busy; extern icnt_drain_p icnt_drain; +extern icnt_display_stats_p icnt_display_stats; +extern icnt_display_overall_stats_p icnt_display_overall_stats; +extern icnt_display_state_p icnt_display_state; extern icnt_get_flit_size_p icnt_get_flit_size; extern int g_network_mode; @@ -54,8 +63,7 @@ enum network_mode { N_NETWORK_MODE }; -void icnt_init( unsigned int n_shader, unsigned int n_mem ); +void icnt_wrapper_init( unsigned int n_shader, unsigned int n_mem ); void icnt_reg_options( class OptionParser * opp ); -void display_icnt_state( FILE *fp ); #endif diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index 2bfc7e9..c5fc44e 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -38,7 +38,7 @@ #include "gpu-cache.h" #include "histogram.h" #include "l2cache.h" -#include "../intersim/statwraper.h" +#include "../statwrapper.h" #include "../abstract_hardware_model.h" #include "gpu-sim.h" #include "shader.h" diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index eb3748f..df858fa 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -40,8 +40,7 @@ #include "mem_fetch.h" #include "mem_latency_stat.h" #include "visualizer.h" -#include "../intersim/statwraper.h" -#include "../intersim/interconnect_interface.h" +#include "../statwrapper.h" #include "icnt_wrapper.h" #include <string.h> #include <limits.h> diff --git a/src/intersim2/Makefile b/src/intersim2/Makefile new file mode 100644 index 0000000..a0a04e9 --- /dev/null +++ b/src/intersim2/Makefile @@ -0,0 +1,176 @@ +# $Id $ + +# Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +# All rights reserved. +# +# 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 following disclaimer. +# Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 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 THE COPYRIGHT OWNER 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. + +# +# Makefile +# +CXX = g++ +CC = gcc +CREATE_LIBRARY ?= 0 +INTERFACE = interconnect_interface.cpp +DEBUG ?= 0 + +LEX = flex +YACC = bison -y +DEFINE = #-DTRACK_STALLS -DTRACK_BUFFERS -DTRACK_FLOWS -DTRACK_CREDITS +INCPATH = -I. -Iarbiters -Iallocators -Irouters -Inetworks -Ipower + +ifeq ($(CREATE_LIBRARY),1) +INCPATH += -I$(GPGPUSIM_ROOT)/src/gpgpu-sim/ +endif + +CPPFLAGS += -Wall $(INCPATH) $(DEFINE) +ifneq ($(DEBUG),1) +CPPFLAGS += -O3 +endif +CPPFLAGS += -g +CPPFLAGS += -fPIC +LFLAGS += + + +ifeq ($(SIM_OBJ_FILES_DIR),) +OBJDIR := obj +else +OBJDIR := $(SIM_OBJ_FILES_DIR)/intersim2 +endif +PROG := booksim + +# simulator source files +CPP_SRCS = \ + config_utils.cpp \ + booksim_config.cpp \ + module.cpp \ + buffer.cpp \ + vc.cpp \ + routefunc.cpp \ + traffic.cpp \ + flitchannel.cpp \ + trafficmanager.cpp \ + batchtrafficmanager.cpp \ + packet_reply_info.cpp \ + buffer_state.cpp \ + stats.cpp \ + credit.cpp \ + outputset.cpp \ + flit.cpp \ + injection.cpp\ + misc_utils.cpp\ + rng_wrapper.cpp\ + rng_double_wrapper.cpp\ + power_module.cpp \ + switch_monitor.cpp \ + buffer_monitor.cpp \ + main.cpp \ + gputrafficmanager.cpp \ + intersim_config.cpp + +ifeq ($(CREATE_LIBRARY),1) +CPP_SRCS += $(INTERFACE) +DEFINE += -DCREATE_LIBRARY +endif + + +LEX_OBJS = ${OBJDIR}/lex.yy.o +YACC_OBJS = ${OBJDIR}/y.tab.o + +# networks +NETWORKS:= $(wildcard networks/*.cpp) +ALLOCATORS:= $(wildcard allocators/*.cpp) +ARBITERS:= $(wildcard arbiters/*.cpp) +ROUTERS:= $(wildcard routers/*.cpp) +POWER:= $(wildcard power/*.cpp) + +#--- Make rules --- +OBJS := $(LEX_OBJS) $(YACC_OBJS)\ + $(CPP_SRCS:%.cpp=${OBJDIR}/%.o)\ + $(NETWORKS:networks/%.cpp=${OBJDIR}/%.o)\ + $(ALLOCATORS:allocators/%.cpp=${OBJDIR}/%.o)\ + $(ARBITERS:arbiters/%.cpp=${OBJDIR}/%.o)\ + $(ROUTERS:routers/%.cpp=${OBJDIR}/%.o)\ + $(POWER:power/%.cpp=${OBJDIR}/%.o) + +.PHONY: clean + +ifeq ($(CREATE_LIBRARY),1) +all: $(OBJS) +else +all:$(PROG) + +$(PROG): $(OBJS) + $(CXX) $(LFLAGS) $^ -o $@ +endif + +# rules to compile simulator + + +${LEX_OBJS}: lex.yy.c y.tab.h + $(CC) $(CPPFLAGS) -c $< -o $@ + +${YACC_OBJS}: y.tab.c y.tab.h + $(CC) $(CPPFLAGS) -c $< -o $@ + +${OBJDIR}/%.o: %.cpp + $(CXX) $(CPPFLAGS) -c $< -o $@ + +# rules to compile networks +${OBJDIR}/%.o: networks/%.cpp + $(CXX) $(CPPFLAGS) -c $< -o $@ + +# rules to compile arbiters +${OBJDIR}/%.o: arbiters/%.cpp + $(CXX) $(CPPFLAGS) -c $< -o $@ + +# rules to compile allocators +${OBJDIR}/%.o: allocators/%.cpp + $(CXX) $(CPPFLAGS) -c $< -o $@ + +# rules to compile routers +${OBJDIR}/%.o: routers/%.cpp + $(CXX) $(CPPFLAGS) -c $< -o $@ + +# rules to compile power classes +${OBJDIR}/%.o: power/%.cpp + $(CXX) $(CPPFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) + rm -f $(PROG) + rm -f *~ + rm -f allocators/*~ + rm -f arbiters/*~ + rm -f networks/*~ + rm -f runfiles/*~ + rm -f routers/*~ + rm -f examples/*~ + rm -f y.tab.c y.tab.h lex.yy.c + rm -f moc_bgui.cpp + +y.tab.c y.tab.h: config.y + $(YACC) -d $< + +lex.yy.c: config.l + $(LEX) $< +# DO NOT DELETE diff --git a/src/intersim2/allocators/allocator.cpp b/src/intersim2/allocators/allocator.cpp new file mode 100644 index 0000000..5940ac5 --- /dev/null +++ b/src/intersim2/allocators/allocator.cpp @@ -0,0 +1,481 @@ +// $Id: allocator.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <iostream> +#include <sstream> +#include <cassert> +#include "allocator.hpp" + +///////////////////////////////////////////////////////////////////////// +//Allocator types +#include "maxsize.hpp" +#include "pim.hpp" +#include "islip.hpp" +#include "loa.hpp" +#include "wavefront.hpp" +#include "selalloc.hpp" +#include "separable_input_first.hpp" +#include "separable_output_first.hpp" +// +///////////////////////////////////////////////////////////////////////// + +//================================================== +// Allocator base class +//================================================== + +Allocator::Allocator( Module *parent, const string& name, + int inputs, int outputs ) : +Module( parent, name ), _inputs( inputs ), _outputs( outputs ), _dirty( false ) +{ + _inmatch.resize(_inputs, -1); + _outmatch.resize(_outputs, -1); +} + +void Allocator::Clear( ) +{ + if(_dirty) { + _inmatch.assign(_inputs, -1); + _outmatch.assign(_outputs, -1); + _dirty = false; + } +} + +void Allocator::AddRequest( int in, int out, int label, int in_pri, + int out_pri ) { + + assert( ( in >= 0 ) && ( in < _inputs ) ); + assert( ( out >= 0 ) && ( out < _outputs ) ); + assert( label >= 0 ); + _dirty = true; +} + +int Allocator::OutputAssigned( int in ) const +{ + assert( ( in >= 0 ) && ( in < _inputs ) ); + + return _inmatch[in]; +} + +int Allocator::InputAssigned( int out ) const +{ + assert( ( out >= 0 ) && ( out < _outputs ) ); + + return _outmatch[out]; +} + +void Allocator::PrintGrants( ostream * os ) const +{ + if(!os) os = &cout; + + *os << "Input grants = [ "; + for ( int input = 0; input < _inputs; ++input ) { + if(_inmatch[input] >= 0) { + *os << input << " -> " << _inmatch[input] << " "; + } + } + *os << "], output grants = [ "; + for ( int output = 0; output < _outputs; ++output ) { + if(_outmatch[output] >= 0) { + *os << output << " -> " << _outmatch[output] << " "; + } + } + *os << "]." << endl; +} + +//================================================== +// DenseAllocator +//================================================== + +DenseAllocator::DenseAllocator( Module *parent, const string& name, + int inputs, int outputs ) : + Allocator( parent, name, inputs, outputs ) +{ + _request.resize(_inputs); + + for ( int i = 0; i < _inputs; ++i ) { + _request[i].resize(_outputs); + for ( int j = 0; j < _outputs; ++j ) { + _request[i][j].label = -1; + } + } +} + +void DenseAllocator::Clear( ) +{ + for ( int i = 0; i < _inputs; ++i ) { + for ( int j = 0; j < _outputs; ++j ) { + _request[i][j].label = -1; + } + } + Allocator::Clear(); +} + +int DenseAllocator::ReadRequest( int in, int out ) const +{ + assert( ( in >= 0 ) && ( in < _inputs ) ); + assert( ( out >= 0 ) && ( out < _outputs ) ); + + return _request[in][out].label; +} + +bool DenseAllocator::ReadRequest( sRequest &req, int in, int out ) const +{ + assert( ( in >= 0 ) && ( in < _inputs ) ); + assert( ( out >= 0 ) && ( out < _outputs ) ); + + req = _request[in][out]; + + return ( req.label >= 0 ); +} + +void DenseAllocator::AddRequest( int in, int out, int label, + int in_pri, int out_pri ) +{ + Allocator::AddRequest(in, out, label, in_pri, out_pri); + assert( _request[in][out].label == -1 ); + + _request[in][out].label = label; + _request[in][out].in_pri = in_pri; + _request[in][out].out_pri = out_pri; +} + +void DenseAllocator::RemoveRequest( int in, int out, int label ) +{ + assert( ( in >= 0 ) && ( in < _inputs ) ); + assert( ( out >= 0 ) && ( out < _outputs ) ); + + _request[in][out].label = -1; +} + +bool DenseAllocator::InputHasRequests( int in ) const +{ + for(int out = 0; out < _outputs; ++out) { + if(_request[in][out].label >= 0) { + return true; + } + } + return false; +} + +bool DenseAllocator::OutputHasRequests( int out ) const +{ + for(int in = 0; in < _inputs; ++in) { + if(_request[in][out].label >= 0) { + return true; + } + } + return false; +} + +int DenseAllocator::NumInputRequests( int in ) const +{ + int result = 0; + for(int out = 0; out < _outputs; ++out) { + if(_request[in][out].label >= 0) { + ++result; + } + } + return result; +} + +int DenseAllocator::NumOutputRequests( int out ) const +{ + int result = 0; + for(int in = 0; in < _inputs; ++in) { + if(_request[in][out].label >= 0) { + ++result; + } + } + return result; +} + +void DenseAllocator::PrintRequests( ostream * os ) const +{ + if(!os) os = &cout; + + *os << "Input requests = [ "; + for ( int input = 0; input < _inputs; ++input ) { + bool print = false; + ostringstream ss; + for ( int output = 0; output < _outputs; ++output ) { + const sRequest & req = _request[input][output]; + if ( req.label >= 0 ) { + print = true; + ss << output << "@" << req.in_pri << " "; + } + } + if(print) { + *os << input << " -> [ " << ss.str() << "] "; + } + } + *os << "], output requests = [ "; + for ( int output = 0; output < _outputs; ++output ) { + bool print = false; + ostringstream ss; + for ( int input = 0; input < _inputs; ++input ) { + const sRequest & req = _request[input][output]; + if ( req.label >= 0 ) { + print = true; + ss << input << "@" << req.out_pri << " "; + } + } + if(print) { + *os << output << " -> [ " << ss.str() << "] "; + } + } + *os << "]." << endl; +} + +//================================================== +// SparseAllocator +//================================================== + +SparseAllocator::SparseAllocator( Module *parent, const string& name, + int inputs, int outputs ) : + Allocator( parent, name, inputs, outputs ) +{ + _in_req.resize(_inputs); + _out_req.resize(_outputs); +} + + +void SparseAllocator::Clear( ) +{ + for ( int i = 0; i < _inputs; ++i ) { + if(!_in_req[i].empty()) + _in_req[i].clear( ); + } + + for ( int j = 0; j < _outputs; ++j ) { + if(!_out_req[j].empty()) + _out_req[j].clear( ); + } + + _in_occ.clear( ); + _out_occ.clear( ); + + Allocator::Clear(); +} + +int SparseAllocator::ReadRequest( int in, int out ) const +{ + sRequest r; + + if ( ! ReadRequest( r, in, out ) ) { + r.label = -1; + } + + return r.label; +} + +bool SparseAllocator::ReadRequest( sRequest &req, int in, int out ) const +{ + bool found; + + assert( ( in >= 0 ) && ( in < _inputs ) ); + assert( ( out >= 0 ) && ( out < _outputs ) ); + + map<int, sRequest>::const_iterator match = _in_req[in].find(out); + if ( match != _in_req[in].end( ) ) { + req = match->second; + found = true; + } else { + found = false; + } + + return found; +} + +void SparseAllocator::AddRequest( int in, int out, int label, + int in_pri, int out_pri ) +{ + Allocator::AddRequest(in, out, label, in_pri, out_pri); + assert( _in_req[in].count(out) == 0 ); + assert( _out_req[out].count(in) == 0 ); + + // insert into occupied inputs set if + // input is currently empty + if ( _in_req[in].empty( ) ) { + _in_occ.insert(in); + } + + // similarly for the output + if ( _out_req[out].empty( ) ) { + _out_occ.insert(out); + } + + sRequest req; + req.port = out; + req.label = label; + req.in_pri = in_pri; + req.out_pri = out_pri; + + _in_req[in][out] = req; + + req.port = in; + + _out_req[out][in] = req; +} + +void SparseAllocator::RemoveRequest( int in, int out, int label ) +{ + assert( ( in >= 0 ) && ( in < _inputs ) ); + assert( ( out >= 0 ) && ( out < _outputs ) ); + + assert( _in_req[in].count( out ) > 0 ); + assert( _in_req[in][out].label == label ); + _in_req[in].erase( out ); + + // remove from occupied inputs list if + // input is now empty + if ( _in_req[in].empty( ) ) { + _in_occ.erase(in); + } + + // similarly for the output + assert( _out_req[out].count( in ) > 0 ); + assert( _out_req[out][in].label == label ); + _out_req[out].erase( in ); + + if ( _out_req[out].empty( ) ) { + _out_occ.erase(out); + } +} + +bool SparseAllocator::InputHasRequests( int in ) const +{ + return _in_occ.count(in) > 0; +} + +bool SparseAllocator::OutputHasRequests( int out ) const +{ + return _out_occ.count(out) > 0; +} + +int SparseAllocator::NumInputRequests( int in ) const +{ + return _in_occ.count(in); +} + +int SparseAllocator::NumOutputRequests( int out ) const +{ + return _out_occ.count(out); +} + +void SparseAllocator::PrintRequests( ostream * os ) const +{ + map<int, sRequest>::const_iterator iter; + + if(!os) os = &cout; + + *os << "Input requests = [ "; + for ( int input = 0; input < _inputs; ++input ) { + if(!_in_req[input].empty()) { + *os << input << " -> [ "; + for ( iter = _in_req[input].begin( ); + iter != _in_req[input].end( ); iter++ ) { + *os << iter->second.port << "@" << iter->second.in_pri << " "; + } + *os << "] "; + } + } + *os << "], output requests = [ "; + for ( int output = 0; output < _outputs; ++output ) { + if(!_out_req[output].empty()) { + *os << output << " -> "; + *os << "[ "; + for ( iter = _out_req[output].begin( ); + iter != _out_req[output].end( ); iter++ ) { + *os << iter->second.port << "@" << iter->second.out_pri << " "; + } + *os << "] "; + } + } + *os << "]." << endl; +} + +//================================================== +// Global allocator allocation function +//================================================== + +Allocator *Allocator::NewAllocator( Module *parent, const string& name, + const string &alloc_type, + int inputs, int outputs, + Configuration const * const config ) +{ + Allocator *a = 0; + + string alloc_name; + string param_str; + size_t left = alloc_type.find_first_of('('); + if(left == string::npos) { + alloc_name = alloc_type; + } else { + alloc_name = alloc_type.substr(0, left); + size_t right = alloc_type.find_last_of(')'); + if(right == string::npos) { + param_str = alloc_type.substr(left+1); + } else { + param_str = alloc_type.substr(left+1, right-left-1); + } + } + if ( alloc_name == "max_size" ) { + a = new MaxSizeMatch( parent, name, inputs, outputs ); + } else if ( alloc_name == "pim" ) { + int iters = param_str.empty() ? (config ? config->GetInt("alloc_iters") : 1) : atoi(param_str.c_str()); + a = new PIM( parent, name, inputs, outputs, iters ); + } else if ( alloc_name == "islip" ) { + int iters = param_str.empty() ? (config ? config->GetInt("alloc_iters") : 1) : atoi(param_str.c_str()); + a = new iSLIP_Sparse( parent, name, inputs, outputs, iters ); + } else if ( alloc_name == "loa" ) { + a = new LOA( parent, name, inputs, outputs ); + } else if ( alloc_name == "wavefront" ) { + a = new Wavefront( parent, name, inputs, outputs ); + } else if ( alloc_name == "rr_wavefront" ) { + a = new Wavefront( parent, name, inputs, outputs, true ); + } else if ( alloc_name == "select" ) { + int iters = param_str.empty() ? (config ? config->GetInt("alloc_iters") : 1) : atoi(param_str.c_str()); + a = new SelAlloc( parent, name, inputs, outputs, iters ); + } else if (alloc_name == "separable_input_first") { + string arb_type = param_str.empty() ? (config ? config->GetStr("arb_type") : "round_robin") : param_str; + a = new SeparableInputFirstAllocator( parent, name, inputs, outputs, + arb_type ); + } else if (alloc_name == "separable_output_first") { + string arb_type = param_str.empty() ? (config ? config->GetStr("arb_type") : "round_robin") : param_str; + a = new SeparableOutputFirstAllocator( parent, name, inputs, outputs, + arb_type ); + } + +//================================================== +// Insert new allocators here, add another else if +//================================================== + + + return a; +} + diff --git a/src/intersim2/allocators/allocator.hpp b/src/intersim2/allocators/allocator.hpp new file mode 100644 index 0000000..ea4441a --- /dev/null +++ b/src/intersim2/allocators/allocator.hpp @@ -0,0 +1,158 @@ +// $Id: allocator.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _ALLOCATOR_HPP_ +#define _ALLOCATOR_HPP_ + +#include <string> +#include <map> +#include <set> +#include <vector> + +#include "module.hpp" +#include "config_utils.hpp" + +class Allocator : public Module { +protected: + const int _inputs; + const int _outputs; + + bool _dirty; + + vector<int> _inmatch; + vector<int> _outmatch; + +public: + + struct sRequest { + int port; + int label; + int in_pri; + int out_pri; + }; + + Allocator( Module *parent, const string& name, + int inputs, int outputs ); + + virtual void Clear( ); + + virtual int ReadRequest( int in, int out ) const = 0; + virtual bool ReadRequest( sRequest &req, int in, int out ) const = 0; + + virtual void AddRequest( int in, int out, int label = 1, + int in_pri = 0, int out_pri = 0 ); + virtual void RemoveRequest( int in, int out, int label = 1 ) = 0; + + virtual void Allocate( ) = 0; + + int OutputAssigned( int in ) const; + int InputAssigned( int out ) const; + + virtual bool OutputHasRequests( int out ) const = 0; + virtual bool InputHasRequests( int in ) const = 0; + + virtual int NumOutputRequests( int out ) const = 0; + virtual int NumInputRequests( int in ) const = 0; + + virtual void PrintRequests( ostream * os = NULL ) const = 0; + void PrintGrants( ostream * os = NULL ) const; + + static Allocator *NewAllocator( Module *parent, const string& name, + const string &alloc_type, + int inputs, int outputs, + Configuration const * const config = NULL ); +}; + +//================================================== +// A dense allocator stores the entire request +// matrix. +//================================================== + +class DenseAllocator : public Allocator { +protected: + vector<vector<sRequest> > _request; + +public: + DenseAllocator( Module *parent, const string& name, + int inputs, int outputs ); + + void Clear( ); + + int ReadRequest( int in, int out ) const; + bool ReadRequest( sRequest &req, int in, int out ) const; + + void AddRequest( int in, int out, int label = 1, + int in_pri = 0, int out_pri = 0 ); + void RemoveRequest( int in, int out, int label = 1 ); + + bool OutputHasRequests( int out ) const; + bool InputHasRequests( int in ) const; + + int NumOutputRequests( int out ) const; + int NumInputRequests( int in ) const; + + void PrintRequests( ostream * os = NULL ) const; + +}; + +//================================================== +// A sparse allocator only stores the requests +// (allows for a more efficient implementation). +//================================================== + +class SparseAllocator : public Allocator { +protected: + set<int> _in_occ; + set<int> _out_occ; + + vector<map<int, sRequest> > _in_req; + vector<map<int, sRequest> > _out_req; + +public: + SparseAllocator( Module *parent, const string& name, + int inputs, int outputs ); + + void Clear( ); + + int ReadRequest( int in, int out ) const; + bool ReadRequest( sRequest &req, int in, int out ) const; + + void AddRequest( int in, int out, int label = 1, + int in_pri = 0, int out_pri = 0 ); + void RemoveRequest( int in, int out, int label = 1 ); + + bool OutputHasRequests( int out ) const; + bool InputHasRequests( int in ) const; + + int NumOutputRequests( int out ) const; + int NumInputRequests( int in ) const; + + void PrintRequests( ostream * os = NULL ) const; + +}; + +#endif diff --git a/src/intersim2/allocators/islip.cpp b/src/intersim2/allocators/islip.cpp new file mode 100644 index 0000000..ab8f53d --- /dev/null +++ b/src/intersim2/allocators/islip.cpp @@ -0,0 +1,183 @@ +// $Id: islip.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <iostream> + +#include "islip.hpp" +#include "random_utils.hpp" + +//#define DEBUG_ISLIP + +iSLIP_Sparse::iSLIP_Sparse( Module *parent, const string& name, + int inputs, int outputs, int iters ) : + SparseAllocator( parent, name, inputs, outputs ), + _iSLIP_iter(iters) +{ + _gptrs.resize(_outputs, 0); + _aptrs.resize(_inputs, 0); +} + +void iSLIP_Sparse::Allocate( ) +{ + int input; + int output; + + int input_offset; + int output_offset; + + map<int, sRequest>::iterator p; + bool wrapped; + + for ( int iter = 0; iter < _iSLIP_iter; ++iter ) { + // Grant phase + + vector<int> grants(_outputs, -1); + + for ( output = 0; output < _outputs; ++output ) { + + // Skip loop if there are no requests + // or the output is already matched + if ( ( _out_req[output].empty( ) ) || + ( _outmatch[output] != -1 ) ) { + continue; + } + + // A round-robin arbiter between input requests + input_offset = _gptrs[output]; + + p = _out_req[output].begin( ); + while( ( p != _out_req[output].end( ) ) && + ( p->second.port < input_offset ) ) { + p++; + } + + wrapped = false; + while( (!wrapped) || + ( ( p != _out_req[output].end( ) ) && + ( p->second.port < input_offset ) ) ) { + if ( p == _out_req[output].end( ) ) { + if ( wrapped ) { break; } + // p is valid here because empty lists + // are skipped (above) + p = _out_req[output].begin( ); + wrapped = true; + } + + input = p->second.port; + + // we know the output is free (above) and + // if the input is free, grant request + if ( _inmatch[input] == -1 ) { + grants[output] = input; + break; + } + + p++; + } + } + +#ifdef DEBUG_ISLIP + cout << "grants: "; + for ( int i = 0; i < _outputs; ++i ) { + cout << grants[i] << " "; + } + cout << endl; + + cout << "aptrs: "; + for ( int i = 0; i < _inputs; ++i ) { + cout << _aptrs[i] << " "; + } + cout << endl; +#endif + + // Accept phase + + for ( input = 0; input < _inputs; ++input ) { + + if ( _in_req[input].empty( ) ) { + continue; + } + + // A round-robin arbiter between output grants + output_offset = _aptrs[input]; + + p = _in_req[input].begin( ); + while( ( p != _in_req[input].end( ) ) && + ( p->second.port < output_offset ) ) { + p++; + } + + wrapped = false; + while( (!wrapped) || + ( ( p != _in_req[input].end( ) ) && + ( p->second.port < output_offset ) ) ) { + if ( p == _in_req[input].end( ) ) { + if ( wrapped ) { break; } + // p is valid here because empty lists + // are skipped (above) + p = _in_req[input].begin( ); + wrapped = true; + } + + output = p->second.port; + + // we know the output is free (above) and + // if the input is free, grant request + if ( grants[output] == input ) { + // Accept + _inmatch[input] = output; + _outmatch[output] = input; + + // Only update pointers if accepted during the 1st iteration + if ( iter == 0 ) { + _gptrs[output] = ( input + 1 ) % _inputs; + _aptrs[input] = ( output + 1 ) % _outputs; + } + + break; + } + + p++; + } + } + } + +#ifdef DEBUG_ISLIP + cout << "input match: "; + for ( int i = 0; i < _inputs; ++i ) { + cout << _inmatch[i] << " "; + } + cout << endl; + + cout << "output match: "; + for ( int j = 0; j < _outputs; ++j ) { + cout << _outmatch[j] << " "; + } + cout << endl; +#endif +} diff --git a/src/intersim2/allocators/islip.hpp b/src/intersim2/allocators/islip.hpp new file mode 100644 index 0000000..c0c5d2a --- /dev/null +++ b/src/intersim2/allocators/islip.hpp @@ -0,0 +1,48 @@ +// $Id: islip.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _ISLIP_HPP_ +#define _ISLIP_HPP_ + +#include <vector> + +#include "allocator.hpp" + +class iSLIP_Sparse : public SparseAllocator { + int _iSLIP_iter; + + vector<int> _gptrs; + vector<int> _aptrs; + +public: + iSLIP_Sparse( Module *parent, const string& name, + int inputs, int outputs, int iters ); + + void Allocate( ); +}; + +#endif diff --git a/src/intersim2/allocators/loa.cpp b/src/intersim2/allocators/loa.cpp new file mode 100644 index 0000000..c24bbe3 --- /dev/null +++ b/src/intersim2/allocators/loa.cpp @@ -0,0 +1,112 @@ +// $Id: loa.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <iostream> + +#include "loa.hpp" +#include "random_utils.hpp" + +LOA::LOA( Module *parent, const string& name, + int inputs, int outputs ) : + DenseAllocator( parent, name, inputs, outputs ) +{ + _req.resize(inputs); + _counts.resize(outputs); + + _rptr.resize(inputs); + _gptr.resize(outputs); +} + +void LOA::Allocate( ) +{ + int input; + int output; + + int input_offset; + int output_offset; + + int lonely; + int lonely_cnt; + + // Count phase --- the number of requests + // per output is counted + + for ( int j = 0; j < _outputs; ++j ) { + _counts[j] = 0; + for ( int i = 0; i < _inputs; ++i ) { + _counts[j] += ( _request[i][j].label != -1 ) ? 1 : 0; + } + } + + // Request phase + for ( input = 0; input < _inputs; ++input ) { + + // Find the lonely output + output_offset = _rptr[input]; + lonely = -1; + lonely_cnt = _inputs + 1; + + for ( int o = 0; o < _outputs; ++o ) { + output = ( o + output_offset ) % _outputs; + + if ( ( _request[input][output].label != -1 ) && + ( _counts[output] < lonely_cnt ) ) { + lonely = output; + lonely_cnt = _counts[output]; + } + } + + // Request the lonely output (-1 for no request) + _req[input] = lonely; + } + + // Grant phase + for ( output = 0; output < _outputs; ++output ) { + input_offset = _gptr[output]; + + for ( int i = 0; i < _inputs; ++i ) { + input = ( i + input_offset ) % _inputs; + + if ( _req[input] == output ) { + // Grant! + + _inmatch[input] = output; + _outmatch[output] = input; + + _rptr[input] = ( _rptr[input] + 1 ) % _outputs; + _gptr[output] = ( _gptr[output] + 1 ) % _inputs; + + break; + } + } + } + + +} + + diff --git a/src/intersim2/allocators/loa.hpp b/src/intersim2/allocators/loa.hpp new file mode 100644 index 0000000..c119c31 --- /dev/null +++ b/src/intersim2/allocators/loa.hpp @@ -0,0 +1,49 @@ +// $Id: loa.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _LOA_HPP_ +#define _LOA_HPP_ + +#include <vector> + +#include "allocator.hpp" + +class LOA : public DenseAllocator { + vector<int> _counts; + vector<int> _req; + + vector<int> _rptr; + vector<int> _gptr; + +public: + LOA( Module *parent, const string& name, + int inputs, int outputs ); + + void Allocate( ); +}; + +#endif diff --git a/src/intersim2/allocators/maxsize.cpp b/src/intersim2/allocators/maxsize.cpp new file mode 100644 index 0000000..ce18dae --- /dev/null +++ b/src/intersim2/allocators/maxsize.cpp @@ -0,0 +1,210 @@ +// $Id: maxsize.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + Neither the name of the Stanford University 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <iostream> + +#include "maxsize.hpp" + +// shortest augmenting path: +// +// for all unmatched left nodes, +// push node onto work stack +// end +// +// for all j, +// from[j] = undefined +// end +// +// do, +// +// while( !stack.empty ), +// +// nl = stack.pop +// for each edge (nl,j), +// if ( ( lmatch[nl] != j ) && ( from[j] == undefined ) ), +// if ( rmatch[j] == undefined ), +// stop // augmenting path found +// else +// from[j] = nl +// newstack.push( rmatch[j] ) +// end +// end +// end +// end +// +// stack = newstack +// end +// + +//#define DEBUG_MAXSIZE +//#define PRINT_MATCHING + +MaxSizeMatch::MaxSizeMatch( Module *parent, const string& name, + int inputs, int outputs ) : + DenseAllocator( parent, name, inputs, outputs ) +{ + _from.resize(outputs); + _s = new int [inputs]; + _ns = new int [inputs]; + _prio = 0; +} + +MaxSizeMatch::~MaxSizeMatch( ) +{ + delete [] _s; + delete [] _ns; +} + +void MaxSizeMatch::Allocate( ) +{ + + // augment as many times as possible + // (this is an O(N^3) maximum-size matching algorithm) + while( _ShortestAugmenting( ) ); + + // next time, start at next input to ensure fairness + _prio = (_prio + 1) % _inputs; +} + + +bool MaxSizeMatch::_ShortestAugmenting( ) +{ + int i, j, jn; + int slen, nslen; + + // start with empty stack + slen = 0; + + // push all unassigned inputs to the stack + for ( i = 0; i < _inputs; ++i ) { + j = (i + _prio) % _inputs; + if ( _inmatch[j] == -1 ) { // start with unmatched left nodes + _s[slen++] = j; + } + } + + _from.assign(_inputs, -1); + + for ( int iter = 0; iter < _inputs; iter++ ) { + nslen = 0; + + for ( int e = 0; e < slen; ++e ) { + i = _s[e]; + + for ( j = 0; j < _outputs; ++j ) { + if ( ( _request[i][j].label != -1 ) && // edge (i,j) exists + ( _inmatch[i] != j ) && // (i,j) is not contained in the current matching + ( _from[j] == -1 ) ) { // no shorter path to j exists + + _from[j] = i; // how did we get to j? + +#ifdef DEBUG_MAXSIZE + cout << " got to " << j << " from " << i << endl; +#endif + if ( _outmatch[j] == -1 ) { // j is unmatched -- augmenting path found + goto found_augmenting; + } else { // j is matched + _ns[nslen] = _outmatch[j]; // add the destination of this edge to the leaf nodes + nslen++; + +#ifdef DEBUG_MAXSIZE + cout << " adding " << _outmatch[j] << endl; +#endif + } + } + } + } + + // no augmenting path found yet, swap stacks + int * t = _s; + _s = _ns; + _ns = t; + slen = nslen; + } + + return false; // no augmenting paths + + found_augmenting: + + // the augmenting path ends at node j on the right + +#ifdef DEBUG_MAXSIZE + cout << "Found path: " << j << "c <- "; +#endif + + i = _from[j]; + _outmatch[j] = i; + +#ifdef DEBUG_MAXSIZE + cout << i; +#endif + + while ( _inmatch[i] != -1 ) { // loop until the end of the path + jn = _inmatch[i]; // remove previous edge (i,jn) and add (i,j) + _inmatch[i] = j; + +#ifdef DEBUG_MAXSIZE + cout << " <- " << j << "c <- "; +#endif + + j = jn; // add edge from (jn,in) + i = _from[j]; + _outmatch[j] = i; + +#ifdef DEBUG_MAXSIZE + cout << i; +#endif + } + +#ifdef DEBUG_MAXSIZE + cout << endl; +#endif + + _inmatch[i] = j; + +#ifdef PRINT_MATCHING + cout << "left matching: "; + + for ( i = 0; i < _inputs; i++ ) { + cout << _inmatch[i] << " "; + } + cout << endl; + + cout << "right matching: "; + for ( i = 0; i < _outputs; i++ ) { + cout << _outmatch[i] << " "; + } + cout << endl; +#endif + + return true; +} diff --git a/src/intersim2/allocators/maxsize.hpp b/src/intersim2/allocators/maxsize.hpp new file mode 100644 index 0000000..3a1afe9 --- /dev/null +++ b/src/intersim2/allocators/maxsize.hpp @@ -0,0 +1,51 @@ +// $Id: maxsize.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _MAXSIZE_HPP_ +#define _MAXSIZE_HPP_ + +#include <vector> + +#include "allocator.hpp" + +class MaxSizeMatch : public DenseAllocator { + vector<int> _from; // array to hold breadth-first tree + int *_s; // stack of leaf nodes in tree + int *_ns; // next stack + int _prio; // priority pointer to ensure fairness + + bool _ShortestAugmenting( ); + +public: + MaxSizeMatch( Module *parent, const string& name, + int inputs, int ouputs ); + ~MaxSizeMatch( ); + + void Allocate( ); +}; + +#endif diff --git a/src/intersim2/allocators/pim.cpp b/src/intersim2/allocators/pim.cpp new file mode 100644 index 0000000..487a6d6 --- /dev/null +++ b/src/intersim2/allocators/pim.cpp @@ -0,0 +1,120 @@ +// $Id: pim.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <iostream> + +#include "pim.hpp" +#include "random_utils.hpp" + +//#define DEBUG_PIM + +PIM::PIM( Module *parent, const string& name, + int inputs, int outputs, int iters ) : + DenseAllocator( parent, name, inputs, outputs ), + _PIM_iter(iters) +{ +} + +PIM::~PIM( ) +{ +} + +void PIM::Allocate( ) +{ + int input; + int output; + + int input_offset; + int output_offset; + + for ( int iter = 0; iter < _PIM_iter; ++iter ) { + // Grant phase --- outputs randomly choose + // between one of their requests + + vector<int> grants(_outputs, -1); + + for ( output = 0; output < _outputs; ++output ) { + + // A random arbiter between input requests + input_offset = RandomInt( _inputs - 1 ); + + for ( int i = 0; i < _inputs; ++i ) { + input = ( i + input_offset ) % _inputs; + + if ( ( _request[input][output].label != -1 ) && + ( _inmatch[input] == -1 ) && + ( _outmatch[output] == -1 ) ) { + + // Grant + grants[output] = input; + break; + } + } + } + + // Accept phase -- inputs randomly choose + // between input_speedup of their grants + + for ( input = 0; input < _inputs; ++input ) { + + // A random arbiter between output grants + output_offset = RandomInt( _outputs - 1 ); + + for ( int o = 0; o < _outputs; ++o ) { + output = ( o + output_offset ) % _outputs; + + if ( grants[output] == input ) { + + // Accept + _inmatch[input] = output; + _outmatch[output] = input; + + break; + } + } + } + } + +#ifdef DEBUG_PIM + if ( _outputs == 8 ) { + cout << "input match: " << endl; + for ( int i = 0; i < _inputs; ++i ) { + cout << " from " << i << " to " << _inmatch[i] << endl; + } + cout << endl; + } + + cout << "output match: "; + for ( int j = 0; j < _outputs; ++j ) { + cout << _outmatch[j] << " "; + } + cout << endl; +#endif +} + + diff --git a/src/intersim2/allocators/pim.hpp b/src/intersim2/allocators/pim.hpp new file mode 100644 index 0000000..e4d709b --- /dev/null +++ b/src/intersim2/allocators/pim.hpp @@ -0,0 +1,47 @@ +// $Id: pim.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _PIM_HPP_ +#define _PIM_HPP_ + +#include <vector> + +#include "allocator.hpp" + +class PIM : public DenseAllocator { + int _PIM_iter; + +public: + PIM( Module *parent, const string& name, + int inputs, int outputs, int iters ); + + ~PIM( ); + + void Allocate( ); +}; + +#endif diff --git a/src/intersim2/allocators/selalloc.cpp b/src/intersim2/allocators/selalloc.cpp new file mode 100644 index 0000000..df42143 --- /dev/null +++ b/src/intersim2/allocators/selalloc.cpp @@ -0,0 +1,254 @@ +// $Id: selalloc.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <iostream> + +#include "selalloc.hpp" +#include "random_utils.hpp" + +//#define DEBUG_SELALLOC + +SelAlloc::SelAlloc( Module *parent, const string& name, + int inputs, int outputs, int iters ) : + SparseAllocator( parent, name, inputs, outputs ) +{ + _iter = iters; + + _gptrs.resize(outputs, 0); + _aptrs.resize(inputs, 0); + _outmask.resize(outputs, 0); +} + +void SelAlloc::Allocate( ) +{ + int input; + int output; + + int input_offset; + int output_offset; + + map<int, sRequest>::iterator p; + set<int>::iterator outer_iter; + bool wrapped; + + int max_index; + int max_pri; + + vector<int> grants(_outputs, -1); + + for ( int iter = 0; iter < _iter; ++iter ) { + // Grant phase + + for( outer_iter = _out_occ.begin( ); + outer_iter != _out_occ.end( ); ++outer_iter ) { + output = *outer_iter; + + // Skip loop if there are no requests + // or the output is already matched or + // the output is masked + if ( ( _out_req[output].empty( ) ) || + ( _outmatch[output] != -1 ) || + ( _outmask[output] != 0 ) ) { + continue; + } + + // A round-robin arbiter between input requests + input_offset = _gptrs[output]; + + p = _out_req[output].begin( ); + while( ( p != _out_req[output].end( ) ) && + ( p->second.port < input_offset ) ) { + p++; + } + + max_index = -1; + max_pri = 0; + + wrapped = false; + while( (!wrapped) || + ( ( p != _out_req[output].end() ) && + ( p->second.port < input_offset ) ) ) { + if ( p == _out_req[output].end( ) ) { + if ( wrapped ) { break; } + // p is valid here because empty lists + // are skipped (above) + p = _out_req[output].begin( ); + wrapped = true; + } + + input = p->second.port; + + // we know the output is free (above) and + // if the input is free, check if request is the + // highest priority so far + if ( ( _inmatch[input] == -1 ) && + ( ( p->second.out_pri > max_pri ) || ( max_index == -1 ) ) ) { + max_pri = p->second.out_pri; + max_index = input; + } + + p++; + } + + if ( max_index != -1 ) { // grant + grants[output] = max_index; + } + } + +#ifdef DEBUG_SELALLOC + cout << "grants: "; + for ( int i = 0; i < _outputs; ++i ) { + cout << grants[i] << " "; + } + cout << endl; + + cout << "aptrs: "; + for ( int i = 0; i < _inputs; ++i ) { + cout << _aptrs[i] << " "; + } + cout << endl; +#endif + + // Accept phase + + for ( outer_iter = _in_occ.begin( ); + outer_iter != _in_occ.end( ); ++outer_iter ) { + input = *outer_iter; + + if ( _in_req[input].empty( ) ) { + continue; + } + + // A round-robin arbiter between output grants + output_offset = _aptrs[input]; + + p = _in_req[input].begin( ); + while( ( p != _in_req[input].end( ) ) && + ( p->second.port < output_offset ) ) { + p++; + } + + max_index = -1; + max_pri = 0; + + wrapped = false; + while( (!wrapped) || + ( ( p != _in_req[input].end() ) && + ( p->second.port < output_offset ) ) ) { + if ( p == _in_req[input].end( ) ) { + if ( wrapped ) { break; } + // p is valid here because empty lists + // are skipped (above) + p = _in_req[input].begin( ); + wrapped = true; + } + + output = p->second.port; + + // we know the output is free (above) and + // if the input is free, check if the highest + // priroity + if ( ( grants[output] == input ) && + ( !_out_req[output].empty( ) ) && + ( ( p->second.in_pri > max_pri ) || ( max_index == -1 ) ) ) { + max_pri = p->second.in_pri; + max_index = output; + } + + p++; + } + + if ( max_index != -1 ) { + // Accept + output = max_index; + + _inmatch[input] = output; + _outmatch[output] = input; + + // Only update pointers if accepted during the 1st iteration + if ( iter == 0 ) { + _gptrs[output] = ( input + 1 ) % _inputs; + _aptrs[input] = ( output + 1 ) % _outputs; + } + } + } + } + +#ifdef DEBUG_SELALLOC + cout << "input match: "; + for ( int i = 0; i < _inputs; ++i ) { + cout << _inmatch[i] << " "; + } + cout << endl; + + cout << "output match: "; + for ( int j = 0; j < _outputs; ++j ) { + cout << _outmatch[j] << " "; + } + cout << endl; +#endif +} + +void SelAlloc::MaskOutput( int out, int mask ) +{ + assert( ( out >= 0 ) && ( out < _outputs ) ); + _outmask[out] = mask; +} + +void SelAlloc::PrintRequests( ostream * os ) const +{ + map<int, sRequest>::const_iterator iter; + + if(!os) os = &cout; + + *os << "Input requests = [ "; + for ( int input = 0; input < _inputs; ++input ) { + *os << input << " -> [ "; + for ( iter = _in_req[input].begin( ); + iter != _in_req[input].end( ); iter++ ) { + *os << iter->second.port << " "; + } + *os << "] "; + } + *os << "], output requests = [ "; + for ( int output = 0; output < _outputs; ++output ) { + *os << output << " -> "; + if ( _outmask[output] == 0 ) { + *os << "[ "; + for ( iter = _out_req[output].begin( ); + iter != _out_req[output].end( ); iter++ ) { + *os << iter->second.port << " "; + } + *os << "] "; + } else { + *os << "masked "; + } + } + *os << "]." << endl; +} + diff --git a/src/intersim2/allocators/selalloc.hpp b/src/intersim2/allocators/selalloc.hpp new file mode 100644 index 0000000..9a0fe8c --- /dev/null +++ b/src/intersim2/allocators/selalloc.hpp @@ -0,0 +1,55 @@ +// $Id: selalloc.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _SELALLOC_HPP_ +#define _SELALLOC_HPP_ + +#include <vector> + +#include "allocator.hpp" + +class SelAlloc : public SparseAllocator { + int _iter; + + vector<int> _aptrs; + vector<int> _gptrs; + + vector<int> _outmask; + +public: + SelAlloc( Module *parent, const string& name, + int inputs, int outputs, int iters ); + + void Allocate( ); + + void MaskOutput( int out, int mask = 1 ); + + virtual void PrintRequests( ostream * os = NULL ) const; + +}; + +#endif diff --git a/src/intersim2/allocators/separable.cpp b/src/intersim2/allocators/separable.cpp new file mode 100644 index 0000000..dc15da6 --- /dev/null +++ b/src/intersim2/allocators/separable.cpp @@ -0,0 +1,86 @@ +// $Id: separable.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// SeparableAllocator: Separable Allocator Base Class +// +// ---------------------------------------------------------------------- + +#include "separable.hpp" + +#include <sstream> + +#include "arbiter.hpp" + +SeparableAllocator::SeparableAllocator( Module* parent, const string& name, + int inputs, int outputs, + const string& arb_type ) + : SparseAllocator( parent, name, inputs, outputs ) +{ + + _input_arb.resize(inputs); + + for (int i = 0; i < inputs; ++i) { + ostringstream arb_name("arb_i"); + arb_name << i; + _input_arb[i] = Arbiter::NewArbiter(this, arb_name.str(), arb_type, outputs); + } + + _output_arb.resize(outputs); + + for (int i = 0; i < outputs; ++i) { + ostringstream arb_name("arb_o"); + arb_name << i; + _output_arb[i] = Arbiter::NewArbiter(this, arb_name.str( ), arb_type, inputs); + } + +} + +SeparableAllocator::~SeparableAllocator() { + + for (int i = 0; i < _inputs; ++i) { + delete _input_arb[i]; + } + + for (int i = 0; i < _outputs; ++i) { + delete _output_arb[i]; + } + +} + +void SeparableAllocator::Clear() { + for ( int i = 0 ; i < _inputs ; i++ ) { + if(_input_arb[i]-> _num_reqs) + _input_arb[i]->Clear(); + } + for ( int o = 0; o < _outputs; o++ ) { + if(_output_arb[o]->_num_reqs) + _output_arb[o]->Clear(); + } + SparseAllocator::Clear(); +} diff --git a/src/intersim2/allocators/separable.hpp b/src/intersim2/allocators/separable.hpp new file mode 100644 index 0000000..afd1efc --- /dev/null +++ b/src/intersim2/allocators/separable.hpp @@ -0,0 +1,61 @@ +// $Id: separable.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// SeparableAllocator: Separable Allocator Base Class +// +// ---------------------------------------------------------------------- + +#ifndef _SEPARABLE_HPP_ +#define _SEPARABLE_HPP_ + +#include <vector> + +#include "allocator.hpp" + +class Arbiter; + +class SeparableAllocator : public SparseAllocator { + +protected: + + vector<Arbiter*> _input_arb ; + vector<Arbiter*> _output_arb ; + +public: + + SeparableAllocator( Module* parent, const string& name, int inputs, + int outputs, const string& arb_type ) ; + + virtual ~SeparableAllocator() ; + + virtual void Clear() ; + +} ; + +#endif diff --git a/src/intersim2/allocators/separable_input_first.cpp b/src/intersim2/allocators/separable_input_first.cpp new file mode 100644 index 0000000..3a682fa --- /dev/null +++ b/src/intersim2/allocators/separable_input_first.cpp @@ -0,0 +1,103 @@ +// $Id: separable_input_first.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// SeparableInputFirstAllocator: Separable Input-First Allocator +// +// ---------------------------------------------------------------------- + +#include "separable_input_first.hpp" + +#include "booksim.hpp" +#include "arbiter.hpp" + +#include <vector> +#include <iostream> +#include <cstring> + +SeparableInputFirstAllocator:: +SeparableInputFirstAllocator( Module* parent, const string& name, int inputs, + int outputs, const string& arb_type ) + : SeparableAllocator( parent, name, inputs, outputs, arb_type ) +{} + +void SeparableInputFirstAllocator::Allocate() { + + set<int>::const_iterator port_iter = _in_occ.begin(); + while(port_iter != _in_occ.end()) { + + const int & input = *port_iter; + + // add requests to the input arbiter + + map<int, sRequest>::const_iterator req_iter = _in_req[input].begin(); + while(req_iter != _in_req[input].end()) { + + const sRequest & req = req_iter->second; + + _input_arb[input]->AddRequest(req.port, req.label, req.in_pri); + + ++req_iter; + } + + // Execute the input arbiters and propagate the grants to the + // output arbiters. + + int label = -1; + const int output = _input_arb[input]->Arbitrate(&label, NULL); + assert(output > -1); + + const sRequest & req = _out_req[output][input]; + assert((req.port == input) && (req.label == label)); + + _output_arb[output]->AddRequest(req.port, req.label, req.out_pri); + + ++port_iter; + } + + port_iter = _out_occ.begin(); + while(port_iter != _out_occ.end()) { + + const int & output = *port_iter; + + // Execute the output arbiters. + + const int input = _output_arb[output]->Arbitrate(NULL, NULL); + + if(input > -1) { + assert((_inmatch[input] == -1) && (_outmatch[output] == -1)); + + _inmatch[input] = output ; + _outmatch[output] = input ; + _input_arb[input]->UpdateState() ; + _output_arb[output]->UpdateState() ; + } + + ++port_iter; + } +} diff --git a/src/intersim2/allocators/separable_input_first.hpp b/src/intersim2/allocators/separable_input_first.hpp new file mode 100644 index 0000000..c9ded06 --- /dev/null +++ b/src/intersim2/allocators/separable_input_first.hpp @@ -0,0 +1,52 @@ +// $Id: separable_input_first.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// SeparableInputFirstAllocator: Separable Input-First Allocator +// +// ---------------------------------------------------------------------- + +#ifndef _SEPARABLE_INPUT_FIRST_HPP_ +#define _SEPARABLE_INPUT_FIRST_HPP_ + +#include <set> + +#include "separable.hpp" + +class SeparableInputFirstAllocator : public SeparableAllocator { + +public: + + SeparableInputFirstAllocator( Module* parent, const string& name, int inputs, + int outputs, const string& arb_type ) ; + + virtual void Allocate() ; + +} ; + +#endif diff --git a/src/intersim2/allocators/separable_output_first.cpp b/src/intersim2/allocators/separable_output_first.cpp new file mode 100644 index 0000000..b72658f --- /dev/null +++ b/src/intersim2/allocators/separable_output_first.cpp @@ -0,0 +1,103 @@ +// $Id: separable_output_first.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// SeparableOutputFirstAllocator: Separable Output-First Allocator +// +// ---------------------------------------------------------------------- + +#include "separable_output_first.hpp" + +#include "booksim.hpp" +#include "arbiter.hpp" + +#include <vector> +#include <iostream> +#include <cstring> + +SeparableOutputFirstAllocator:: +SeparableOutputFirstAllocator( Module* parent, const string& name, int inputs, + int outputs, const string& arb_type ) + : SeparableAllocator( parent, name, inputs, outputs, arb_type ) +{} + +void SeparableOutputFirstAllocator::Allocate() { + + set<int>::const_iterator port_iter = _out_occ.begin(); + while(port_iter != _out_occ.end()) { + + const int & output = *port_iter; + + // add requests to the output arbiter + + map<int, sRequest>::const_iterator req_iter = _out_req[output].begin(); + while(req_iter != _out_req[output].end()) { + + const sRequest & req = req_iter->second; + + _output_arb[output]->AddRequest(req.port, req.label, req.out_pri); + + ++req_iter; + } + + // Execute the output arbiter and propagate the grants to the + // input arbiters. + + int label = -1; + const int input = _output_arb[output]->Arbitrate(&label, NULL); + assert(input > -1); + + const sRequest & req = _in_req[input][output]; + assert((req.port == output) && (req.label == label)); + + _input_arb[input]->AddRequest(req.port, req.label, req.in_pri); + + ++port_iter; + } + + port_iter = _in_occ.begin(); + while(port_iter != _in_occ.end()) { + + const int & input = *port_iter; + + // Execute the input arbiters. + + const int output = _input_arb[input]->Arbitrate(NULL, NULL); + + if(output > -1) { + assert((_inmatch[input] == -1) && (_outmatch[output] == -1)); + + _inmatch[input] = output; + _outmatch[output] = input; + _input_arb[input]->UpdateState() ; + _output_arb[output]->UpdateState() ; + } + + ++port_iter; + } +} diff --git a/src/intersim2/allocators/separable_output_first.hpp b/src/intersim2/allocators/separable_output_first.hpp new file mode 100644 index 0000000..1103f0d --- /dev/null +++ b/src/intersim2/allocators/separable_output_first.hpp @@ -0,0 +1,50 @@ +// $Id: separable_output_first.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// SeparableOutputFirstAllocator: Separable Output-First Allocator +// +// ---------------------------------------------------------------------- + +#ifndef _SEPARABLE_OUTPUT_FIRST_HPP_ +#define _SEPARABLE_OUTPUT_FIRST_HPP_ + +#include "separable.hpp" + +class SeparableOutputFirstAllocator : public SeparableAllocator { + +public: + + SeparableOutputFirstAllocator( Module* parent, const string& name, int inputs, + int outputs, const string& arb_type ) ; + + virtual void Allocate() ; + +} ; + +#endif diff --git a/src/intersim2/allocators/wavefront.cpp b/src/intersim2/allocators/wavefront.cpp new file mode 100644 index 0000000..39a4427 --- /dev/null +++ b/src/intersim2/allocators/wavefront.cpp @@ -0,0 +1,111 @@ +// $Id: wavefront.cpp 5262 2012-09-20 23:39:40Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*wavefront.cpp + * + *The wave front allocator + * + */ +#include "booksim.hpp" + +#include "wavefront.hpp" + +Wavefront::Wavefront( Module *parent, const string& name, + int inputs, int outputs, bool skip_diags ) : + DenseAllocator( parent, name, inputs, outputs ), + _last_in(-1), _last_out(-1), _skip_diags(skip_diags), + _square(max(inputs, outputs)), _pri(0), _num_requests(0) +{ +} + +void Wavefront::AddRequest( int in, int out, int label, + int in_pri, int out_pri ) +{ + DenseAllocator::AddRequest(in, out, label, in_pri, out_pri); + _num_requests++; + _last_in = in; + _last_out = out; + _priorities.insert(make_pair(out_pri, in_pri)); +} + +void Wavefront::Allocate( ) +{ + + int first_diag = -1; + + if(_num_requests == 0) + + // bypass allocator completely if there were no requests + return; + + if(_num_requests == 1) { + + // if we only had a single request, we can immediately grant it + _inmatch[_last_in] = _last_out; + _outmatch[_last_out] = _last_in; + first_diag = _last_in + _last_out; + + } else { + + // otherwise we have to loop through the diagonals of request matrix + + for(set<pair<int, int> >::const_reverse_iterator iter = + _priorities.rbegin(); + iter != _priorities.rend(); ++iter) { + + for ( int p = 0; p < _square; ++p ) { + for ( int output = 0; output < _square; ++output ) { + int input = ( ( _pri + p ) + ( _square - output ) ) % _square; + if ( ( input < _inputs ) && ( output < _outputs ) && + ( _inmatch[input] == -1 ) && ( _outmatch[output] == -1 ) && + ( _request[input][output].label != -1 ) && + ( _request[input][output].in_pri == iter->second ) && + ( _request[input][output].out_pri == iter->first ) ) { + // Grant! + _inmatch[input] = output; + _outmatch[output] = input; + if(first_diag < 0) { + first_diag = input + output; + } + } + } + } + } + } + + _num_requests = 0; + _last_in = -1; + _last_out = -1; + _priorities.clear(); + + assert(first_diag >= 0); + + // Round-robin the priority diagonal + _pri = ( ( _skip_diags ? first_diag : _pri ) + 1 ) % _square; +} + + diff --git a/src/intersim2/allocators/wavefront.hpp b/src/intersim2/allocators/wavefront.hpp new file mode 100644 index 0000000..0c36a36 --- /dev/null +++ b/src/intersim2/allocators/wavefront.hpp @@ -0,0 +1,57 @@ +// $Id: wavefront.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _WAVEFRONT_HPP_ +#define _WAVEFRONT_HPP_ + +#include <set> + +#include "allocator.hpp" + +class Wavefront : public DenseAllocator { + +private: + int _last_in; + int _last_out; + set<pair<int, int> > _priorities; + bool _skip_diags; + +protected: + int _square; + int _pri; + int _num_requests; + +public: + Wavefront( Module *parent, const string& name, + int inputs, int outputs, bool skip_diags = false ); + + virtual void AddRequest( int in, int out, int label = 1, + int in_pri = 0, int out_pri = 0 ); + virtual void Allocate( ); +}; + +#endif diff --git a/src/intersim2/arbiters/arbiter.cpp b/src/intersim2/arbiters/arbiter.cpp new file mode 100644 index 0000000..5b4b38f --- /dev/null +++ b/src/intersim2/arbiters/arbiter.cpp @@ -0,0 +1,111 @@ +// $Id: arbiter.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// Arbiter: Base class for Matrix and Round Robin Arbiter +// +// ---------------------------------------------------------------------- + +#include "arbiter.hpp" +#include "roundrobin_arb.hpp" +#include "matrix_arb.hpp" +#include "tree_arb.hpp" + +#include <limits> +#include <cassert> + +using namespace std ; + +Arbiter::Arbiter( Module *parent, const string &name, int size ) + : Module( parent, name ), + _size(size), _selected(-1), _highest_pri(numeric_limits<int>::min()), + _best_input(-1), _num_reqs(0) +{ + _request.resize(size); + for ( int i = 0 ; i < size ; i++ ) + _request[i].valid = false ; +} + +void Arbiter::AddRequest( int input, int id, int pri ) +{ + assert( 0 <= input && input < _size ) ; + assert( !_request[input].valid ); + + _num_reqs++ ; + _request[input].valid = true ; + _request[input].id = id ; + _request[input].pri = pri ; +} + +int Arbiter::Arbitrate( int* id, int* pri ) +{ + if ( _selected != -1 ) { + if ( id ) + *id = _request[_selected].id ; + if ( pri ) + *pri = _request[_selected].pri ; + } + + assert((_selected >= 0) || (_num_reqs == 0)); + + return _selected ; +} + +void Arbiter::Clear() +{ + if(_num_reqs > 0) { + + // clear the request vector + for ( int i = 0; i < _size ; i++ ) + _request[i].valid = false ; + _num_reqs = 0 ; + _selected = -1; + } +} + +Arbiter *Arbiter::NewArbiter( Module *parent, const string& name, + const string &arb_type, int size) +{ + Arbiter *a = NULL; + if(arb_type == "round_robin") { + a = new RoundRobinArbiter( parent, name, size ); + } else if(arb_type == "matrix") { + a = new MatrixArbiter( parent, name, size ); + } else if(arb_type.substr(0, 5) == "tree(") { + size_t left = 4; + size_t middle = arb_type.find_first_of(','); + assert(middle != string::npos); + size_t right = arb_type.find_last_of(')'); + assert(right != string::npos); + string groups_str = arb_type.substr(left+1, middle-left-1); + int groups = atoi(groups_str.c_str()); + string sub_arb_type = arb_type.substr(middle+1, right-middle-1); + a = new TreeArbiter( parent, name, size, groups, sub_arb_type ); + } else assert(false); + return a; +} diff --git a/src/intersim2/arbiters/arbiter.hpp b/src/intersim2/arbiters/arbiter.hpp new file mode 100644 index 0000000..456bd8f --- /dev/null +++ b/src/intersim2/arbiters/arbiter.hpp @@ -0,0 +1,86 @@ +// $Id: arbiter.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// Arbiter: Base class for Matrix and Round Robin Arbiter +// +// ---------------------------------------------------------------------- + +#ifndef _ARBITER_HPP_ +#define _ARBITER_HPP_ + +#include <vector> + +#include "module.hpp" + +class Arbiter : public Module { + +protected: + + typedef struct { + bool valid ; + int id ; + int pri ; + } entry_t ; + + vector<entry_t> _request ; + int _size ; + + int _selected ; + int _highest_pri; + int _best_input; + +public: + int _num_reqs ; + // Constructors + Arbiter( Module *parent, const string &name, int size ) ; + + // Print priority matrix to standard output + virtual void PrintState() const = 0 ; + + // Register request with arbiter + virtual void AddRequest( int input, int id, int pri ) ; + + // Update priority matrix based on last aribtration result + virtual void UpdateState() = 0 ; + + // Arbitrate amongst requests. Returns winning input and + // updates pointers to metadata when valid pointers are passed + virtual int Arbitrate( int* id = 0, int* pri = 0 ) ; + + virtual void Clear(); + + inline int LastWinner() const { + return _selected; + } + + static Arbiter *NewArbiter( Module *parent, const string &name, + const string &arb_type, int size ); +} ; + +#endif diff --git a/src/intersim2/arbiters/matrix_arb.cpp b/src/intersim2/arbiters/matrix_arb.cpp new file mode 100644 index 0000000..d087e19 --- /dev/null +++ b/src/intersim2/arbiters/matrix_arb.cpp @@ -0,0 +1,121 @@ +// $Id: matrix_arb.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// Matrix: Matrix Arbiter +// +// ---------------------------------------------------------------------- + +#include "matrix_arb.hpp" +#include <iostream> +using namespace std ; + +MatrixArbiter::MatrixArbiter( Module *parent, const string &name, int size ) + : Arbiter( parent, name, size ), _last_req(-1) { + _matrix.resize(size); + for ( int i = 0 ; i < size ; i++ ) { + _matrix[i].resize(size); + for ( int j = 0; j < i; j++ ) { + _matrix[i][j] = 1; + } + } +} + +void MatrixArbiter::PrintState() const { + cout << "Priority Matrix: " << endl ; + for ( int r = 0; r < _size ; r++ ) { + for ( int c = 0 ; c < _size ; c++ ) { + cout << _matrix[r][c] << " " ; + } + cout << endl ; + } + cout << endl ; +} + +void MatrixArbiter::UpdateState() { + // update priority matrix using last grant + if ( _selected > -1 ) { + for ( int i = 0; i < _size ; i++ ) { + if( _selected != i ) { + _matrix[_selected][i] = 0 ; + _matrix[i][_selected] = 1 ; + } + } + } +} + +void MatrixArbiter::AddRequest( int input, int id, int pri ) +{ + _last_req = input; + Arbiter::AddRequest(input, id, pri); +} + +int MatrixArbiter::Arbitrate( int* id, int* pri ) { + + // avoid running arbiter if it has not recevied at least two requests + // (in this case, requests and grants are identical) + if ( _num_reqs < 2 ) { + + _selected = _last_req ; + + } else { + + _selected = -1 ; + + for ( int input = 0 ; input < _size ; input++ ) { + if(_request[input].valid) { + + bool grant = true; + for ( int i = 0 ; i < _size ; i++ ) { + if ( _request[i].valid && + ( ( ( _request[i].pri == _request[input].pri ) && + _matrix[i][input]) || + ( _request[i].pri > _request[input].pri ) + ) ) { + grant = false ; + break ; + } + } + + if ( grant ) { + _selected = input ; + break ; + } + } + + } + } + + return Arbiter::Arbitrate(id, pri); +} + +void MatrixArbiter::Clear() +{ + _last_req = -1; + Arbiter::Clear(); +} diff --git a/src/intersim2/arbiters/matrix_arb.hpp b/src/intersim2/arbiters/matrix_arb.hpp new file mode 100644 index 0000000..53d3724 --- /dev/null +++ b/src/intersim2/arbiters/matrix_arb.hpp @@ -0,0 +1,71 @@ +// $Id: matrix_arb.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// Matrix: Matrix Arbiter +// +// ---------------------------------------------------------------------- + +#ifndef _MATRIX_ARB_HPP_ +#define _MATRIX_ARB_HPP_ + +#include <vector> + +#include "arbiter.hpp" + +using namespace std; + +class MatrixArbiter : public Arbiter { + + // Priority matrix + vector<vector<int> > _matrix ; + + int _last_req ; + +public: + + // Constructors + MatrixArbiter( Module *parent, const string &name, int size ) ; + + // Print priority matrix to standard output + virtual void PrintState() const ; + + // Update priority matrix based on last aribtration result + virtual void UpdateState() ; + + // Arbitrate amongst requests. Returns winning input and + // updates pointers to metadata when valid pointers are passed + virtual int Arbitrate( int* id = 0, int* pri = 0) ; + + virtual void AddRequest( int input, int id, int pri ) ; + + virtual void Clear(); + +} ; + +#endif diff --git a/src/intersim2/arbiters/prio_arb.cpp b/src/intersim2/arbiters/prio_arb.cpp new file mode 100644 index 0000000..9de2bc2 --- /dev/null +++ b/src/intersim2/arbiters/prio_arb.cpp @@ -0,0 +1,160 @@ +// $Id: prio_arb.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <cassert> + +#include "prio_arb.hpp" + + +PriorityArbiter::PriorityArbiter( const Configuration &config, + Module *parent, const string& name, + int inputs ) +: Module( parent, name ), _rr_ptr(0), _inputs( inputs ) +{ + +} + +void PriorityArbiter::Clear( ) +{ + _requests.clear( ); +} + +void PriorityArbiter::AddRequest( int in, int label, int pri ) +{ + sRequest r; + list<sRequest>::iterator insert_point; + + r.in = in; r.label = label; r.pri = pri; + + insert_point = _requests.begin( ); + while( ( insert_point != _requests.end( ) ) && + ( insert_point->in < in ) ) { + insert_point++; + } + + bool del = false; + bool add = true; + + // For consistant behavior, delete the existing request + // if it is for the same input and has a higher + // priority + + if ( ( insert_point != _requests.end( ) ) && + ( insert_point->in == in ) ) { + if ( insert_point->pri < pri ) { + del = true; + } else { + add = false; + } + } + + if ( add ) { + _requests.insert( insert_point, r ); + } + + if ( del ) { + _requests.erase( insert_point ); + } +} + +void PriorityArbiter::RemoveRequest( int in, int label ) +{ + list<sRequest>::iterator erase_point; + + erase_point = _requests.begin( ); + while( ( erase_point != _requests.end( ) ) && + ( erase_point->in < in ) ) { + erase_point++; + } + + assert( erase_point != _requests.end( ) ); + _requests.erase( erase_point ); +} + +int PriorityArbiter::Match( ) const +{ + return _match; +} + +void PriorityArbiter::Arbitrate( ) +{ + list<sRequest>::iterator p; + + int max_index, max_pri; + bool wrapped; + + //MERGENOTE + //booksim does not have this if statement + //as far as I can tell they are identical in function + if ( _requests.begin( ) != _requests.end( ) ) { + // A round-robin arbiter between input requests + p = _requests.begin( ); + while( ( p != _requests.end( ) ) && + ( p->in < _rr_ptr ) ) { + p++; + } + + max_index = -1; + max_pri = 0; + + wrapped = false; + while( (!wrapped) || ( p->in < _rr_ptr ) ) { + if ( p == _requests.end( ) ) { + if ( wrapped ) { break; } + // p is valid here because empty lists + // are skipped (above) + p = _requests.begin( ); + wrapped = true; + } + + // check if request is the highest priority so far + if ( ( p->pri > max_pri ) || ( max_index == -1 ) ) { + max_pri = p->pri; + max_index = p->in; + } + + p++; + } + + _match = max_index; // -1 for no match + if ( _match != -1 ) { + _rr_ptr = ( _match + 1 ) % _inputs; + } + + } else { + _match = -1; + } +} + +//MERGENOTE +//added update function to priorityarbiter + +void PriorityArbiter::Update( ) +{ + _rr_ptr = ( _rr_ptr + 1 ) % _inputs; +} diff --git a/src/intersim2/arbiters/prio_arb.hpp b/src/intersim2/arbiters/prio_arb.hpp new file mode 100644 index 0000000..0f7b737 --- /dev/null +++ b/src/intersim2/arbiters/prio_arb.hpp @@ -0,0 +1,68 @@ +// $Id: prio_arb.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _PRIO_ARB_HPP_ +#define _PRIO_ARB_HPP_ + +#include <list> + +#include "module.hpp" +#include "config_utils.hpp" + +class PriorityArbiter : public Module { + int _rr_ptr; + +protected: + const int _inputs; + + struct sRequest { + int in; + int label; + int pri; + }; + + list<sRequest> _requests; + + int _match; + +public: + PriorityArbiter( const Configuration &config, + Module *parent, const string& name, + int inputs ); + + void Clear( ); + + void AddRequest( int in, int label = 0, int pri = 0 ); + void RemoveRequest( int in, int label = 0 ); + + int Match( ) const; + + void Arbitrate( ); + void Update( ); +}; + +#endif diff --git a/src/intersim2/arbiters/roundrobin_arb.cpp b/src/intersim2/arbiters/roundrobin_arb.cpp new file mode 100644 index 0000000..f338381 --- /dev/null +++ b/src/intersim2/arbiters/roundrobin_arb.cpp @@ -0,0 +1,80 @@ +// $Id: roundrobin_arb.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// RoundRobin: RoundRobin Arbiter +// +// ---------------------------------------------------------------------- + +#include "roundrobin_arb.hpp" +#include <iostream> +#include <limits> + +using namespace std ; + +RoundRobinArbiter::RoundRobinArbiter( Module *parent, const string &name, + int size ) + : Arbiter( parent, name, size ), _pointer( 0 ) { +} + +void RoundRobinArbiter::PrintState() const { + cout << "Round Robin Priority Pointer: " << endl ; + cout << " _pointer = " << _pointer << endl ; +} + +void RoundRobinArbiter::UpdateState() { + // update priority matrix using last grant + if ( _selected > -1 ) + _pointer = ( _selected + 1 ) % _size ; +} + +void RoundRobinArbiter::AddRequest( int input, int id, int pri ) +{ + if(!_request[input].valid || (_request[input].pri < pri)) { + if((_num_reqs == 0) || + Supersedes(input, pri, _best_input, _highest_pri, _pointer,_size )) { + _highest_pri = pri; + _best_input = input; + } + } + Arbiter::AddRequest(input, id, pri); +} + +int RoundRobinArbiter::Arbitrate( int* id, int* pri ) { + + _selected = _best_input; + + return Arbiter::Arbitrate(id, pri); +} + +void RoundRobinArbiter::Clear() +{ + _highest_pri = numeric_limits<int>::min(); + _best_input = -1; + Arbiter::Clear(); +} diff --git a/src/intersim2/arbiters/roundrobin_arb.hpp b/src/intersim2/arbiters/roundrobin_arb.hpp new file mode 100644 index 0000000..8062270 --- /dev/null +++ b/src/intersim2/arbiters/roundrobin_arb.hpp @@ -0,0 +1,75 @@ +// $Id: roundrobin_arb.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// RoundRobin: Round Robin Arbiter +// +// ---------------------------------------------------------------------- + +#ifndef _ROUNDROBIN_HPP_ +#define _ROUNDROBIN_HPP_ + +#include "arbiter.hpp" + +class RoundRobinArbiter : public Arbiter { + + // Priority pointer + int _pointer ; + +public: + + // Constructors + RoundRobinArbiter( Module *parent, const string &name, int size ) ; + + // Print priority matrix to standard output + virtual void PrintState() const ; + + // Update priority matrix based on last aribtration result + virtual void UpdateState() ; + + // Arbitrate amongst requests. Returns winning input and + // updates pointers to metadata when valid pointers are passed + virtual int Arbitrate( int* id = 0, int* pri = 0) ; + + virtual void AddRequest( int input, int id, int pri ) ; + + virtual void Clear(); + + static inline bool Supersedes(int input1, int pri1, int input2, int pri2, int offset, int size) + { + // in a round-robin scheme with the given number of positions and current + // offset, should a request at input1 with priority pri1 supersede a + // request at input2 with priority pri2? + return ((pri1 > pri2) || + ((pri1 == pri2) && + (((input1 - offset + size) % size) < ((input2 - offset + size) % size)))); + } + +} ; + +#endif diff --git a/src/intersim2/arbiters/tree_arb.cpp b/src/intersim2/arbiters/tree_arb.cpp new file mode 100644 index 0000000..11033dc --- /dev/null +++ b/src/intersim2/arbiters/tree_arb.cpp @@ -0,0 +1,119 @@ +// $Id: tree_arb.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// TreeArbiter +// +// ---------------------------------------------------------------------- + +#include "tree_arb.hpp" +#include <iostream> +#include <sstream> + +using namespace std ; + +TreeArbiter::TreeArbiter( Module *parent, const string &name, + int size, int groups, const string & arb_type ) + : Arbiter( parent, name, size ) { + assert(size % groups == 0); + _group_arbiters.resize(groups); + _group_reqs.resize(groups, 0); + _group_size = size / groups; + for(int i = 0; i < groups; ++i) { + ostringstream group_arb_name; + group_arb_name << "group_arb" << i; + _group_arbiters[i] = Arbiter::NewArbiter(this, group_arb_name.str(), arb_type, _group_size); + } + _global_arbiter = Arbiter::NewArbiter(this, "global_arb", arb_type, groups); +} + +TreeArbiter::~TreeArbiter() { + for(int i = 0; i < (int)_group_arbiters.size(); ++i) { + delete _group_arbiters[i]; + } + delete _global_arbiter; +} + +void TreeArbiter::PrintState() const { + for(int i = 0; i < (int)_group_arbiters.size(); ++i) { + cout << "Group arbiter " << i << ":" << endl; + _group_arbiters[i]->PrintState(); + } + cout << "Global arbiter:" << endl; + _global_arbiter->PrintState(); +} + +void TreeArbiter::UpdateState() { + if(_selected > -1) { + int last_winner = _global_arbiter->LastWinner(); + assert(last_winner >= 0 && last_winner < (int)_group_arbiters.size()); + _group_arbiters[last_winner]->UpdateState(); + _global_arbiter->UpdateState(); + } +} + +void TreeArbiter::AddRequest( int input, int id, int pri ) +{ + Arbiter::AddRequest(input, id, pri); + int group_index = input / _group_size; + _group_arbiters[group_index]->AddRequest( input % _group_size, id, pri ); + ++_group_reqs[group_index]; +} + +int TreeArbiter::Arbitrate( int* id, int* pri ) { + if(!_num_reqs) { + return -1; + } + for(int i = 0; i < (int)_group_arbiters.size(); ++i) { + if(_group_reqs[i]) { + int group_id, group_pri; + _group_arbiters[i]->Arbitrate(&group_id, &group_pri); + _global_arbiter->AddRequest(i, group_id, group_pri); + } + } + int group = _global_arbiter->Arbitrate(NULL, NULL); + assert(group >= 0 && group < (int)_group_arbiters.size()); + int group_sel = _group_arbiters[group]->LastWinner(); + assert(group_sel >= 0 && group_sel < _group_size); + _selected = group * _group_size + group_sel; + assert(_selected >= 0 && _selected < _size); + return Arbiter::Arbitrate(id, pri); +} + +void TreeArbiter::Clear() +{ + if(!_num_reqs) { + return; + } + for(int i = 0; i < (int)_group_arbiters.size(); ++i) { + _group_arbiters[i]->Clear(); + _group_reqs[i] = 0; + } + _global_arbiter->Clear(); + Arbiter::Clear(); +} diff --git a/src/intersim2/arbiters/tree_arb.hpp b/src/intersim2/arbiters/tree_arb.hpp new file mode 100644 index 0000000..4350e56 --- /dev/null +++ b/src/intersim2/arbiters/tree_arb.hpp @@ -0,0 +1,71 @@ +// $Id: tree_arb.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// TreeArbiter +// +// ---------------------------------------------------------------------- + +#ifndef _TREE_ARB_HPP_ +#define _TREE_ARB_HPP_ + +#include "arbiter.hpp" + +class TreeArbiter : public Arbiter { + + int _group_size ; + + vector<Arbiter *> _group_arbiters; + Arbiter * _global_arbiter; + + vector<int> _group_reqs; + +public: + + // Constructors + TreeArbiter( Module *parent, const string &name, int size, int groups, const string & arb_type ) ; + + ~TreeArbiter(); + + // Print priority matrix to standard output + virtual void PrintState() const ; + + // Update priority matrix based on last aribtration result + virtual void UpdateState() ; + + // Arbitrate amongst requests. Returns winning input and + // updates pointers to metadata when valid pointers are passed + virtual int Arbitrate( int* id = 0, int* pri = 0) ; + + virtual void AddRequest( int input, int id, int pri ) ; + + virtual void Clear(); + +} ; + +#endif diff --git a/src/intersim2/batchtrafficmanager.cpp b/src/intersim2/batchtrafficmanager.cpp new file mode 100644 index 0000000..c32076c --- /dev/null +++ b/src/intersim2/batchtrafficmanager.cpp @@ -0,0 +1,220 @@ +// $Id: batchtrafficmanager.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include <limits> +#include <sstream> +#include <fstream> + +#include "packet_reply_info.hpp" +#include "random_utils.hpp" +#include "batchtrafficmanager.hpp" + +BatchTrafficManager::BatchTrafficManager( const Configuration &config, + const vector<Network *> & net ) +: TrafficManager(config, net), _last_id(-1), _last_pid(-1), + _overall_min_batch_time(0), _overall_avg_batch_time(0), + _overall_max_batch_time(0) +{ + + _max_outstanding = config.GetInt ("max_outstanding_requests"); + + _batch_size = config.GetInt( "batch_size" ); + _batch_count = config.GetInt( "batch_count" ); + + _batch_time = new Stats( this, "batch_time", 1.0, 1000 ); + _stats["batch_time"] = _batch_time; + + string sent_packets_out_file = config.GetStr( "sent_packets_out" ); + if(sent_packets_out_file == "") { + _sent_packets_out = NULL; + } else { + _sent_packets_out = new ofstream(sent_packets_out_file.c_str()); + } +} + +BatchTrafficManager::~BatchTrafficManager( ) +{ + delete _batch_time; + if(_sent_packets_out) delete _sent_packets_out; +} + +void BatchTrafficManager::_RetireFlit( Flit *f, int dest ) +{ + _last_id = f->id; + _last_pid = f->pid; + TrafficManager::_RetireFlit(f, dest); +} + +int BatchTrafficManager::_IssuePacket( int source, int cl ) +{ + int result = 0; + if(_use_read_write[cl]) { //read write packets + //check queue for waiting replies. + //check to make sure it is on time yet + if(!_repliesPending[source].empty()) { + if(_repliesPending[source].front()->time <= _time) { + result = -1; + } + } else { + if((_packet_seq_no[source] < _batch_size) && + ((_max_outstanding <= 0) || + (_requestsOutstanding[source] < _max_outstanding))) { + + //coin toss to determine request type. + result = (RandomFloat() < 0.5) ? 2 : 1; + + _requestsOutstanding[source]++; + } + } + } else { //normal + if((_packet_seq_no[source] < _batch_size) && + ((_max_outstanding <= 0) || + (_requestsOutstanding[source] < _max_outstanding))) { + result = _GetNextPacketSize(cl); + _requestsOutstanding[source]++; + } + } + if(result != 0) { + _packet_seq_no[source]++; + } + return result; +} + +void BatchTrafficManager::_ClearStats( ) +{ + TrafficManager::_ClearStats(); + _batch_time->Clear( ); +} + +bool BatchTrafficManager::_SingleSim( ) +{ + int batch_index = 0; + while(batch_index < _batch_count) { + _packet_seq_no.assign(_nodes, 0); + _last_id = -1; + _last_pid = -1; + _sim_state = running; + int start_time = _time; + bool batch_complete; + cout << "Sending batch " << batch_index + 1 << " (" << _batch_size << " packets)..." << endl; + do { + _Step(); + batch_complete = true; + for(int i = 0; i < _nodes; ++i) { + if(_packet_seq_no[i] < _batch_size) { + batch_complete = false; + break; + } + } + if(_sent_packets_out) { + *_sent_packets_out << _packet_seq_no << endl; + } + } while(!batch_complete); + cout << "Batch injected. Time used is " << _time - start_time << " cycles." << endl; + + int sent_time = _time; + cout << "Waiting for batch to complete..." << endl; + + int empty_steps = 0; + + bool packets_left = false; + for(int c = 0; c < _classes; ++c) { + packets_left |= !_total_in_flight_flits[c].empty(); + } + + while( packets_left ) { + _Step( ); + + ++empty_steps; + + if ( empty_steps % 1000 == 0 ) { + _DisplayRemaining( ); + cout << "."; + } + + packets_left = false; + for(int c = 0; c < _classes; ++c) { + packets_left |= !_total_in_flight_flits[c].empty(); + } + } + cout << endl; + cout << "Batch received. Time used is " << _time - sent_time << " cycles." << endl + << "Last packet was " << _last_pid << ", last flit was " << _last_id << "." << endl; + + _batch_time->AddSample(_time - start_time); + + cout << _sim_state << endl; + + UpdateStats(); + DisplayStats(); + + ++batch_index; + } + _sim_state = draining; + _drain_time = _time; + return 1; +} + +void BatchTrafficManager::_UpdateOverallStats() { + TrafficManager::_UpdateOverallStats(); + _overall_min_batch_time += _batch_time->Min(); + _overall_avg_batch_time += _batch_time->Average(); + _overall_max_batch_time += _batch_time->Max(); +} + +string BatchTrafficManager::_OverallStatsCSV(int c) const +{ + ostringstream os; + os << TrafficManager::_OverallStatsCSV(c) << ',' + << _overall_min_batch_time / (double)_total_sims << ',' + << _overall_avg_batch_time / (double)_total_sims << ',' + << _overall_max_batch_time / (double)_total_sims; + return os.str(); +} + +void BatchTrafficManager::WriteStats(ostream & os) const +{ + TrafficManager::WriteStats(os); + os << "batch_time = " << _batch_time->Average() << ";" << endl; +} + +void BatchTrafficManager::DisplayStats(ostream & os) const { + TrafficManager::DisplayStats(); + os << "Minimum batch duration = " << _batch_time->Min() << endl; + os << "Average batch duration = " << _batch_time->Average() << endl; + os << "Maximum batch duration = " << _batch_time->Max() << endl; +} + +void BatchTrafficManager::DisplayOverallStats(ostream & os) const { + TrafficManager::DisplayOverallStats(os); + os << "Overall min batch duration = " << _overall_min_batch_time / (double)_total_sims + << " (" << _total_sims << " samples)" << endl + << "Overall min batch duration = " << _overall_avg_batch_time / (double)_total_sims + << " (" << _total_sims << " samples)" << endl + << "Overall min batch duration = " << _overall_max_batch_time / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; +} diff --git a/src/intersim2/batchtrafficmanager.hpp b/src/intersim2/batchtrafficmanager.hpp new file mode 100644 index 0000000..4a78e2c --- /dev/null +++ b/src/intersim2/batchtrafficmanager.hpp @@ -0,0 +1,75 @@ +// $Id: batchtrafficmanager.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _BATCHTRAFFICMANAGER_HPP_ +#define _BATCHTRAFFICMANAGER_HPP_ + +#include <iostream> + +#include "config_utils.hpp" +#include "stats.hpp" +#include "trafficmanager.hpp" + +class BatchTrafficManager : public TrafficManager { + +protected: + + int _max_outstanding; + int _batch_size; + int _batch_count; + int _last_id; + int _last_pid; + + Stats * _batch_time; + double _overall_min_batch_time; + double _overall_avg_batch_time; + double _overall_max_batch_time; + + ostream * _sent_packets_out; + + virtual void _RetireFlit( Flit *f, int dest ); + + virtual int _IssuePacket( int source, int cl ); + virtual void _ClearStats( ); + virtual bool _SingleSim( ); + + virtual void _UpdateOverallStats( ); + + virtual string _OverallStatsCSV(int c = 0) const; + +public: + + BatchTrafficManager( const Configuration &config, const vector<Network *> & net ); + virtual ~BatchTrafficManager( ); + + virtual void WriteStats( ostream & os = cout ) const; + virtual void DisplayStats( ostream & os = cout ) const; + virtual void DisplayOverallStats( ostream & os = cout ) const; + +}; + +#endif diff --git a/src/intersim2/booksim.hpp b/src/intersim2/booksim.hpp new file mode 100644 index 0000000..4c55af3 --- /dev/null +++ b/src/intersim2/booksim.hpp @@ -0,0 +1,43 @@ +// $Id: booksim.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _BOOKSIM_HPP_ +#define _BOOKSIM_HPP_ + +#include <string> +#include <cstdlib> +#include <cstring> +#include <climits> +#include <cassert> +#ifdef _WIN32_ +#pragma warning (disable: 4786) +#include <ostream> +#endif + +using namespace std; + +#endif diff --git a/src/intersim2/booksim_config.cpp b/src/intersim2/booksim_config.cpp new file mode 100644 index 0000000..392121b --- /dev/null +++ b/src/intersim2/booksim_config.cpp @@ -0,0 +1,346 @@ +// $Id: booksim_config.cpp 5506 2013-05-07 21:22:23Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*booksim_config.cpp + * + *Contains all the configurable parameters in a network + * + */ + + +#include "booksim.hpp" +#include "booksim_config.hpp" + +BookSimConfig::BookSimConfig( ) +{ + //======================================================== + // Network options + //======================================================== + + // Channel length listing file + AddStrField( "channel_file", "" ) ; + + // Physical sub-networks + _int_map["subnets"] = 1; + + //==== Topology options ======================= + AddStrField( "topology", "torus" ); + _int_map["k"] = 8; //network radix + _int_map["n"] = 2; //network dimension + _int_map["c"] = 1; //concentration + AddStrField( "routing_function", "none" ); + + //simulator tries to correclty adjust latency for node/router placement + _int_map["use_noc_latency"] = 1; + + + //used for noc latency calcualtion for network with concentration + _int_map["x"] = 8; //number of routers in X + _int_map["y"] = 8; //number of routers in Y + _int_map["xr"] = 1; //number of nodes per router in X only if c>1 + _int_map["yr"] = 1; //number of nodes per router in Y only if c>1 + + + _int_map["link_failures"] = 0; //legacy + _int_map["fail_seed"] = 0; //legacy + + //==== Single-node options =============================== + + _int_map["in_ports"] = 5; + _int_map["out_ports"] = 5; + + //======================================================== + // Router options + //======================================================== + + //==== General options =================================== + + AddStrField( "router", "iq" ); + + _int_map["output_delay"] = 0; + _int_map["credit_delay"] = 0; + _float_map["internal_speedup"] = 1.0; + + //with switch speedup flits requires otuput buffering + //full output buffer will cancel switch allocation requests + //default setting is unlimited + _int_map["output_buffer_size"] = -1; + + // enable next-hop-output queueing + _int_map["noq"] = 0; + + //==== Input-queued ====================================== + + // Control of virtual channel speculation + _int_map["speculative"] = 0 ; + _int_map["spec_check_elig"] = 1 ; + _int_map["spec_check_cred"] = 1 ; + _int_map["spec_mask_by_reqs"] = 0 ; + AddStrField("spec_sw_allocator", "prio"); + + _int_map["num_vcs"] = 16; + _int_map["vc_buf_size"] = 8; //per vc buffer size + _int_map["buf_size"] = -1; //shared buffer size + AddStrField("buffer_policy", "private"); //buffer sharing policy + + _int_map["private_bufs"] = -1; + _int_map["private_buf_size"] = 1; + AddStrField("private_buf_size", ""); + _int_map["private_buf_start_vc"] = -1; + AddStrField("private_buf_start_vc", ""); + _int_map["private_buf_end_vc"] = -1; + AddStrField("private_buf_end_vc", ""); + + _int_map["max_held_slots"] = -1; + + _int_map["feedback_aging_scale"] = 1; + _int_map["feedback_offset"] = 0; + + _int_map["wait_for_tail_credit"] = 0; // reallocate a VC before a tail credit? + _int_map["vc_busy_when_full"] = 0; // mark VCs as in use when they have no credit available + _int_map["vc_prioritize_empty"] = 0; // prioritize empty VCs over non-empty ones in VC allocation + _int_map["vc_priority_donation"] = 0; // allow high-priority flits to donate their priority to low-priority that they are queued up behind + _int_map["vc_shuffle_requests"] = 0; // rearrange VC allocator requests to avoid unfairness + + _int_map["hold_switch_for_packet"] = 0; // hold a switch config for the entire packet + + _int_map["input_speedup"] = 1; // expansion of input ports into crossbar + _int_map["output_speedup"] = 1; // expansion of output ports into crossbar + + _int_map["routing_delay"] = 1; + _int_map["vc_alloc_delay"] = 1; + _int_map["sw_alloc_delay"] = 1; + _int_map["st_prepare_delay"] = 0; + _int_map["st_final_delay"] = 1; + + //==== Event-driven ===================================== + + _int_map["vct"] = 0; + + //==== Allocators ======================================== + + AddStrField( "vc_allocator", "islip" ); + AddStrField( "sw_allocator", "islip" ); + + AddStrField( "arb_type", "round_robin" ); + + _int_map["alloc_iters"] = 1; + + //==== Traffic ======================================== + + _int_map["classes"] = 1; + + AddStrField( "traffic", "uniform" ); + + _int_map["class_priority"] = 0; + AddStrField("class_priority", ""); // workaraound to allow for vector specification + + _int_map["perm_seed"] = 0; // seed value for random permuation trafficpattern generator + + _float_map["injection_rate"] = 0.1; + AddStrField("injection_rate", ""); // workaraound to allow for vector specification + + _int_map["injection_rate_uses_flits"] = 0; + + // number of flits per packet + _int_map["packet_size"] = 1; + AddStrField("packet_size", ""); // workaraound to allow for vector specification + + // if multiple values are specified per class, set probabilities for each + _int_map["packet_size_rate"] = 1; + AddStrField("packet_size_rate", ""); // workaraound to allow for vector specification + + AddStrField( "injection_process", "bernoulli" ); + + _float_map["burst_alpha"] = 0.5; // burst interval + _float_map["burst_beta"] = 0.5; // burst length + _float_map["burst_r1"] = -1.0; // burst rate + + AddStrField( "priority", "none" ); // message priorities + + _int_map["batch_size"] = 1000; + _int_map["batch_count"] = 1; + _int_map["max_outstanding_requests"] = 0; // 0 = unlimited + + // Use read/write request reply scheme + _int_map["use_read_write"] = 0; + AddStrField("use_read_write", ""); // workaraound to allow for vector specification + _float_map["write_fraction"] = 0.5; + AddStrField("write_fraction", ""); + + // Control assignment of packets to VCs + _int_map["read_request_begin_vc"] = 0; + _int_map["read_request_end_vc"] = 5; + _int_map["write_request_begin_vc"] = 2; + _int_map["write_request_end_vc"] = 7; + _int_map["read_reply_begin_vc"] = 8; + _int_map["read_reply_end_vc"] = 13; + _int_map["write_reply_begin_vc"] = 10; + _int_map["write_reply_end_vc"] = 15; + + // Control Injection of Packets into Replicated Networks + _int_map["read_request_subnet"] = 0; + _int_map["read_reply_subnet"] = 0; + _int_map["write_request_subnet"] = 0; + _int_map["write_reply_subnet"] = 0; + + // Set packet length in flits + _int_map["read_request_size"] = 1; + AddStrField("read_request_size", ""); // workaraound to allow for vector specification + _int_map["write_request_size"] = 1; + AddStrField("write_request_size", ""); // workaraound to allow for vector specification + _int_map["read_reply_size"] = 1; + AddStrField("read_reply_size", ""); // workaraound to allow for vector specification + _int_map["write_reply_size"] = 1; + AddStrField("write_reply_size", ""); // workaraound to allow for vector specification + + //==== Simulation parameters ========================== + + // types: + // latency - average + latency distribution for a particular injection rate + // throughput - sustained throughput for a particular injection rate + + AddStrField( "sim_type", "latency" ); + + _int_map["warmup_periods"] = 3; // number of samples periods to "warm-up" the simulation + + _int_map["sample_period"] = 1000; // how long between measurements + _int_map["max_samples"] = 10; // maximum number of sample periods in a simulation + + // whether or not to measure statistics for a given traffic class + _int_map["measure_stats"] = 1; + AddStrField("measure_stats", ""); // workaround to allow for vector specification + //whether to enable per pair statistics, caution N^2 memory usage + _int_map["pair_stats"] = 0; + + // if avg. latency exceeds the threshold, assume unstable + _float_map["latency_thres"] = 500.0; + AddStrField("latency_thres", ""); // workaround to allow for vector specification + + // consider warmed up once relative change in latency / throughput between successive iterations is smaller than this + _float_map["warmup_thres"] = 0.05; + AddStrField("warmup_thres", ""); // workaround to allow for vector specification + _float_map["acc_warmup_thres"] = 0.05; + AddStrField("acc_warmup_thres", ""); // workaround to allow for vector specification + + // consider converged once relative change in latency / throughput between successive iterations is smaller than this + _float_map["stopping_thres"] = 0.05; + AddStrField("stopping_thres", ""); // workaround to allow for vector specification + _float_map["acc_stopping_thres"] = 0.05; + AddStrField("acc_stopping_thres", ""); // workaround to allow for vector specification + + _int_map["sim_count"] = 1; // number of simulations to perform + + + _int_map["include_queuing"] =1; // non-zero includes source queuing latency + + // _int_map["reorder"] = 0; // know what you're doing + + //_int_map["flit_timing"] = 0; // know what you're doing + //_int_map["split_packets"] = 0; // know what you're doing + + _int_map["seed"] = 0; //random seed for simulation, e.g. traffic + + _int_map["print_activity"] = 0; + + _int_map["print_csv_results"] = 0; + + _int_map["deadlock_warn_timeout"] = 256; + + _int_map["viewer_trace"] = 0; + + AddStrField("watch_file", ""); + + AddStrField("watch_flits", ""); + AddStrField("watch_packets", ""); + AddStrField("watch_transactions", ""); + + AddStrField("watch_out", ""); + + AddStrField("stats_out", ""); + +#ifdef TRACK_FLOWS + AddStrField("injected_flits_out", ""); + AddStrField("received_flits_out", ""); + AddStrField("stored_flits_out", ""); + AddStrField("sent_flits_out", ""); + AddStrField("outstanding_credits_out", ""); + AddStrField("ejected_flits_out", ""); + AddStrField("active_packets_out", ""); +#endif + +#ifdef TRACK_CREDITS + AddStrField("used_credits_out", ""); + AddStrField("free_credits_out", ""); + AddStrField("max_credits_out", ""); +#endif + + // batch only -- packet sequence numbers + AddStrField("sent_packets_out", ""); + + //==================Power model params===================== + _int_map["sim_power"] = 0; + AddStrField("power_output_file","pwr_tmp"); + AddStrField("tech_file", ""); + _int_map["channel_width"] = 128; + _int_map["channel_sweep"] = 0; + + //==================Network file=========================== + AddStrField("network_file",""); +} + + + +PowerConfig::PowerConfig( ) +{ + + _int_map["H_INVD2"] = 0; + _int_map["W_INVD2"] = 0; + _int_map["H_DFQD1"] = 0; + _int_map["W_DFQD1"] = 0; + _int_map["H_ND2D1"] = 0; + _int_map["W_ND2D1"] = 0; + _int_map["H_SRAM"] = 0; + _int_map["W_SRAM"] = 0; + _float_map["Vdd"] = 0; + _float_map["R"] = 0; + _float_map["IoffSRAM"] = 0; + _float_map["IoffP"] = 0; + _float_map["IoffN"] = 0; + _float_map["Cg_pwr"] = 0; + _float_map["Cd_pwr"] = 0; + _float_map["Cgdl"] = 0; + _float_map["Cg"] = 0; + _float_map["Cd"] = 0; + _float_map["LAMBDA"] = 0; + _float_map["MetalPitch"] = 0; + _float_map["Rw"] = 0; + _float_map["Cw_gnd"] = 0; + _float_map["Cw_cpl"] = 0; + _float_map["wire_length"] = 0; + +} diff --git a/src/intersim2/booksim_config.hpp b/src/intersim2/booksim_config.hpp new file mode 100644 index 0000000..9ecdb40 --- /dev/null +++ b/src/intersim2/booksim_config.hpp @@ -0,0 +1,53 @@ +// $Id: booksim_config.hpp 5487 2013-02-27 08:16:18Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _BOOKSIM_CONFIG_HPP_ +#define _BOOKSIM_CONFIG_HPP_ + +#include "config_utils.hpp" + +class BookSimConfig : public Configuration { +protected: + +public: + BookSimConfig( ); +}; + +#endif + +#ifndef _POWER_CONFIG_HPP_ +#define _POWER_CONFIG_HPP_ + +#include "config_utils.hpp" + +class PowerConfig : public Configuration { +public: + PowerConfig( ); + +}; + +#endif diff --git a/src/intersim2/buffer.cpp b/src/intersim2/buffer.cpp new file mode 100644 index 0000000..25f78e9 --- /dev/null +++ b/src/intersim2/buffer.cpp @@ -0,0 +1,83 @@ +// $Id: buffer.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include <sstream> + +#include "globals.hpp" +#include "booksim.hpp" +#include "buffer.hpp" + +Buffer::Buffer( const Configuration& config, int outputs, + Module *parent, const string& name ) : +Module( parent, name ), _occupancy(0) +{ + int num_vcs = config.GetInt( "num_vcs" ); + + _size = config.GetInt("buf_size"); + if(_size < 0) { + _size = num_vcs * config.GetInt( "vc_buf_size" ); + }; + + _vc.resize(num_vcs); + + for(int i = 0; i < num_vcs; ++i) { + ostringstream vc_name; + vc_name << "vc_" << i; + _vc[i] = new VC(config, outputs, this, vc_name.str( ) ); + } + +#ifdef TRACK_BUFFERS + int classes = config.GetInt("classes"); + _class_occupancy.resize(classes, 0); +#endif +} + +Buffer::~Buffer() +{ + for(vector<VC*>::iterator i = _vc.begin(); i != _vc.end(); ++i) { + delete *i; + } +} + +void Buffer::AddFlit( int vc, Flit *f ) +{ + if(_occupancy >= _size) { + Error("Flit buffer overflow."); + } + ++_occupancy; + _vc[vc]->AddFlit(f); +#ifdef TRACK_BUFFERS + ++_class_occupancy[f->cl]; +#endif +} + +void Buffer::Display( ostream & os ) const +{ + for(vector<VC*>::const_iterator i = _vc.begin(); i != _vc.end(); ++i) { + (*i)->Display(os); + } +} diff --git a/src/intersim2/buffer.hpp b/src/intersim2/buffer.hpp new file mode 100644 index 0000000..a6a0b7a --- /dev/null +++ b/src/intersim2/buffer.hpp @@ -0,0 +1,161 @@ +// $Id: buffer.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _BUFFER_HPP_ +#define _BUFFER_HPP_ + +#include <vector> + +#include "vc.hpp" +#include "flit.hpp" +#include "outputset.hpp" +#include "routefunc.hpp" +#include "config_utils.hpp" + +class Buffer : public Module { + + int _occupancy; + int _size; + + vector<VC*> _vc; + +#ifdef TRACK_BUFFERS + vector<int> _class_occupancy; +#endif + +public: + + Buffer( const Configuration& config, int outputs, + Module *parent, const string& name ); + ~Buffer(); + + void AddFlit( int vc, Flit *f ); + + inline Flit *RemoveFlit( int vc ) + { + --_occupancy; +#ifdef TRACK_BUFFERS + int cl = _vc[vc]->FrontFlit()->cl; + assert(_class_occupancy[cl] > 0); + --_class_occupancy[cl]; +#endif + return _vc[vc]->RemoveFlit( ); + } + + inline Flit *FrontFlit( int vc ) const + { + return _vc[vc]->FrontFlit( ); + } + + inline bool Empty( int vc ) const + { + return _vc[vc]->Empty( ); + } + + inline bool Full( ) const + { + return _occupancy >= _size; + } + + inline VC::eVCState GetState( int vc ) const + { + return _vc[vc]->GetState( ); + } + + inline void SetState( int vc, VC::eVCState s ) + { + _vc[vc]->SetState(s); + } + + inline const OutputSet *GetRouteSet( int vc ) const + { + return _vc[vc]->GetRouteSet( ); + } + + inline void SetRouteSet( int vc, OutputSet * output_set ) + { + _vc[vc]->SetRouteSet(output_set); + } + + inline void SetOutput( int vc, int out_port, int out_vc ) + { + _vc[vc]->SetOutput(out_port, out_vc); + } + + inline int GetOutputPort( int vc ) const + { + return _vc[vc]->GetOutputPort( ); + } + + inline int GetOutputVC( int vc ) const + { + return _vc[vc]->GetOutputVC( ); + } + + inline int GetPriority( int vc ) const + { + return _vc[vc]->GetPriority( ); + } + + inline void Route( int vc, tRoutingFunction rf, const Router* router, const Flit* f, int in_channel ) + { + _vc[vc]->Route(rf, router, f, in_channel); + } + + // ==== Debug functions ==== + + inline void SetWatch( int vc, bool watch = true ) + { + _vc[vc]->SetWatch(watch); + } + + inline bool IsWatched( int vc ) const + { + return _vc[vc]->IsWatched( ); + } + + inline int GetOccupancy( ) const + { + return _occupancy; + } + + inline int GetOccupancy( int vc ) const + { + return _vc[vc]->GetOccupancy( ); + } + +#ifdef TRACK_BUFFERS + inline int GetOccupancyForClass(int c) const + { + return _class_occupancy[c]; + } +#endif + + void Display( ostream & os = cout ) const; +}; + +#endif diff --git a/src/intersim2/buffer_state.cpp b/src/intersim2/buffer_state.cpp new file mode 100644 index 0000000..93492f6 --- /dev/null +++ b/src/intersim2/buffer_state.cpp @@ -0,0 +1,676 @@ +// $Id: buffer_state.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*buffer_state.cpp + * + * This class is the buffere state of the next router down the channel + * tracks the credit and how much of the buffer is in use + */ + +#include <iostream> +#include <sstream> +#include <cstdlib> +#include <cassert> +#include <limits> + +#include "booksim.hpp" +#include "buffer_state.hpp" +#include "random_utils.hpp" +#include "globals.hpp" + +//#define DEBUG_FEEDBACK +//#define DEBUG_SIMPLEFEEDBACK + +BufferState::BufferPolicy::BufferPolicy(Configuration const & config, BufferState * parent, const string & name) +: Module(parent, name), _buffer_state(parent) +{ +} + +void BufferState::BufferPolicy::TakeBuffer(int vc) { +} + +void BufferState::BufferPolicy::SendingFlit(Flit const * const f) { +} + +void BufferState::BufferPolicy::FreeSlotFor(int vc) { +} + +BufferState::BufferPolicy * BufferState::BufferPolicy::New(Configuration const & config, BufferState * parent, const string & name) +{ + BufferPolicy * sp = NULL; + string buffer_policy = config.GetStr("buffer_policy"); + if(buffer_policy == "private") { + sp = new PrivateBufferPolicy(config, parent, name); + } else if(buffer_policy == "shared") { + sp = new SharedBufferPolicy(config, parent, name); + } else if(buffer_policy == "limited") { + sp = new LimitedSharedBufferPolicy(config, parent, name); + } else if(buffer_policy == "dynamic") { + sp = new DynamicLimitedSharedBufferPolicy(config, parent, name); + } else if(buffer_policy == "shifting") { + sp = new ShiftingDynamicLimitedSharedBufferPolicy(config, parent, name); + } else if(buffer_policy == "feedback") { + sp = new FeedbackSharedBufferPolicy(config, parent, name); + } else if(buffer_policy == "simplefeedback") { + sp = new SimpleFeedbackSharedBufferPolicy(config, parent, name); + } else { + cout << "Unknown buffer policy: " << buffer_policy << endl; + } + return sp; +} + +BufferState::PrivateBufferPolicy::PrivateBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : BufferPolicy(config, parent, name) +{ + int const vcs = config.GetInt( "num_vcs" ); + int const buf_size = config.GetInt("buf_size"); + if(buf_size <= 0) { + _vc_buf_size = config.GetInt("vc_buf_size"); + } else { + _vc_buf_size = buf_size / vcs; + } + assert(_vc_buf_size > 0); +} + +void BufferState::PrivateBufferPolicy::SendingFlit(Flit const * const f) +{ + int const vc = f->vc; + if(_buffer_state->OccupancyFor(vc) > _vc_buf_size) { + ostringstream err; + err << "Buffer overflow for VC " << vc; + Error(err.str()); + } +} + +bool BufferState::PrivateBufferPolicy::IsFullFor(int vc) const +{ + return (_buffer_state->OccupancyFor(vc) >= _vc_buf_size); +} + +int BufferState::PrivateBufferPolicy::AvailableFor(int vc) const +{ + return _vc_buf_size - _buffer_state->OccupancyFor(vc); +} + +int BufferState::PrivateBufferPolicy::LimitFor(int vc) const +{ + return _vc_buf_size; +} + +BufferState::SharedBufferPolicy::SharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : BufferPolicy(config, parent, name), _shared_buf_occupancy(0) +{ + int const vcs = config.GetInt( "num_vcs" ); + int num_private_bufs = config.GetInt("private_bufs"); + if(num_private_bufs < 0) { + num_private_bufs = vcs; + } else if(num_private_bufs == 0) { + num_private_bufs = 1; + } + + _private_buf_occupancy.resize(num_private_bufs, 0); + + _buf_size = config.GetInt("buf_size"); + if(_buf_size < 0) { + _buf_size = vcs * config.GetInt("vc_buf_size"); + } + + _private_buf_size = config.GetIntArray("private_buf_size"); + if(_private_buf_size.empty()) { + int const bs = config.GetInt("private_buf_size"); + if(bs < 0) { + _private_buf_size.push_back(_buf_size / num_private_bufs); + } else { + _private_buf_size.push_back(bs); + } + } + _private_buf_size.resize(num_private_bufs, _private_buf_size.back()); + + vector<int> start_vc = config.GetIntArray("private_buf_start_vc"); + if(start_vc.empty()) { + int const sv = config.GetInt("private_buf_start_vc"); + if(sv < 0) { + start_vc.resize(num_private_bufs); + for(int i = 0; i < num_private_bufs; ++i) { + start_vc[i] = i * vcs / num_private_bufs; + } + } else { + start_vc.push_back(sv); + } + } + + vector<int> end_vc = config.GetIntArray("private_buf_end_vc"); + if(end_vc.empty()) { + int const ev = config.GetInt("private_buf_end_vc"); + if(ev < 0) { + end_vc.resize(num_private_bufs); + for(int i = 0; i < num_private_bufs; ++i) { + end_vc[i] = (i + 1) * vcs / num_private_bufs - 1; + } + } else { + end_vc.push_back(ev); + } + } + + _private_buf_vc_map.resize(vcs, -1); + _shared_buf_size = _buf_size; + for(int i = 0; i < num_private_bufs; ++i) { + _shared_buf_size -= _private_buf_size[i]; + assert(start_vc[i] <= end_vc[i]); + for(int v = start_vc[i]; v <= end_vc[i]; ++v) { + assert(_private_buf_vc_map[v] < 0); + _private_buf_vc_map[v] = i; + } + } + assert(_shared_buf_size >= 0); + + _reserved_slots.resize(vcs, 0); +} + +void BufferState::SharedBufferPolicy::ProcessFreeSlot(int vc) +{ + int i = _private_buf_vc_map[vc]; + --_private_buf_occupancy[i]; + if(_private_buf_occupancy[i] < 0) { + ostringstream err; + err << "Private buffer occupancy fell below zero for buffer " << i; + Error(err.str()); + } else if(_private_buf_occupancy[i] >= _private_buf_size[i]) { + --_shared_buf_occupancy; + if(_shared_buf_occupancy < 0) { + Error("Shared buffer occupancy fell below zero."); + } + } +} + +void BufferState::SharedBufferPolicy::SendingFlit(Flit const * const f) +{ + int const vc = f->vc; + if(_reserved_slots[vc] > 0) { + --_reserved_slots[vc]; + } else { + int i = _private_buf_vc_map[vc]; + ++_private_buf_occupancy[i]; + if(_private_buf_occupancy[i] > _private_buf_size[i]) { + ++_shared_buf_occupancy; + if(_shared_buf_occupancy > _shared_buf_size) { + Error("Shared buffer overflow."); + } + } + } + if(f->tail) { + while(_reserved_slots[vc]) { + --_reserved_slots[vc]; + ProcessFreeSlot(vc); + } + } +} + +void BufferState::SharedBufferPolicy::FreeSlotFor(int vc) +{ + if(!_buffer_state->IsAvailableFor(vc) && _buffer_state->IsEmptyFor(vc)) { + ++_reserved_slots[vc]; + } else { + ProcessFreeSlot(vc); + } +} + +bool BufferState::SharedBufferPolicy::IsFullFor(int vc) const +{ + int i = _private_buf_vc_map[vc]; + return ((_reserved_slots[vc] == 0) && + (_private_buf_occupancy[i] >= _private_buf_size[i]) && + (_shared_buf_occupancy >= _shared_buf_size)); +} + +int BufferState::SharedBufferPolicy::AvailableFor(int vc) const +{ + int i = _private_buf_vc_map[vc]; + return (_reserved_slots[vc] + + max(_private_buf_size[i] - _private_buf_occupancy[i], 0) + + (_shared_buf_size - _shared_buf_occupancy)); +} + +int BufferState::SharedBufferPolicy::LimitFor(int vc) const +{ + int i = _private_buf_vc_map[vc]; + return (_private_buf_size[i] + _shared_buf_size); +} + +BufferState::LimitedSharedBufferPolicy::LimitedSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : SharedBufferPolicy(config, parent, name), _active_vcs(0) +{ + _vcs = config.GetInt("num_vcs"); + _max_held_slots = config.GetInt("max_held_slots"); + if(_max_held_slots < 0) { + _max_held_slots = _buf_size; + } +} + +void BufferState::LimitedSharedBufferPolicy::TakeBuffer(int vc) +{ + ++_active_vcs; + if(_active_vcs > _vcs) { + Error("Number of active VCs is too large."); + } +} + +void BufferState::LimitedSharedBufferPolicy::SendingFlit(Flit const * const f) +{ + SharedBufferPolicy::SendingFlit(f); + if(f->tail) { + --_active_vcs; + if(_active_vcs < 0) { + Error("Number of active VCs fell below zero."); + } + } +} + +bool BufferState::LimitedSharedBufferPolicy::IsFullFor(int vc) const +{ + return (SharedBufferPolicy::IsFullFor(vc) || + (_buffer_state->OccupancyFor(vc) >= _max_held_slots)); +} + +int BufferState::LimitedSharedBufferPolicy::AvailableFor(int vc) const +{ + return min(SharedBufferPolicy::AvailableFor(vc), + _max_held_slots - _buffer_state->OccupancyFor(vc)); +} + +int BufferState::LimitedSharedBufferPolicy::LimitFor(int vc) const +{ + return min(SharedBufferPolicy::LimitFor(vc), _max_held_slots); +} + +BufferState::DynamicLimitedSharedBufferPolicy::DynamicLimitedSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : LimitedSharedBufferPolicy(config, parent, name) +{ + _max_held_slots = _buf_size; +} + +void BufferState::DynamicLimitedSharedBufferPolicy::TakeBuffer(int vc) +{ + LimitedSharedBufferPolicy::TakeBuffer(vc); + assert(_active_vcs > 0); + _max_held_slots = _buf_size / _active_vcs; + assert(_max_held_slots > 0); +} + +void BufferState::DynamicLimitedSharedBufferPolicy::SendingFlit(Flit const * const f) +{ + LimitedSharedBufferPolicy::SendingFlit(f); + if(f->tail && _active_vcs) { + _max_held_slots = _buf_size / _active_vcs; + } + assert(_max_held_slots > 0); +} + +BufferState::ShiftingDynamicLimitedSharedBufferPolicy::ShiftingDynamicLimitedSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : DynamicLimitedSharedBufferPolicy(config, parent, name) +{ + +} + +void BufferState::ShiftingDynamicLimitedSharedBufferPolicy::TakeBuffer(int vc) +{ + LimitedSharedBufferPolicy::TakeBuffer(vc); + assert(_active_vcs); + int i = _active_vcs - 1; + _max_held_slots = _buf_size; + while(i) { + _max_held_slots >>= 1; + i >>= 1; + } + assert(_max_held_slots > 0); +} + +void BufferState::ShiftingDynamicLimitedSharedBufferPolicy::SendingFlit(Flit const * const f) +{ + LimitedSharedBufferPolicy::SendingFlit(f); + if(f->tail && _active_vcs) { + int i = _active_vcs - 1; + _max_held_slots = _buf_size; + while(i) { + _max_held_slots >>= 1; + i >>= 1; + } + } + assert(_max_held_slots > 0); +} + +BufferState::FeedbackSharedBufferPolicy::FeedbackSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : SharedBufferPolicy(config, parent, name) +{ + _aging_scale = config.GetInt("feedback_aging_scale"); + _offset = config.GetInt("feedback_offset"); + _vcs = config.GetInt("num_vcs"); + + _occupancy_limit.resize(_vcs, _buf_size); + _round_trip_time.resize(_vcs, -1); + _flit_sent_time.resize(_vcs); + _total_mapped_size = _buf_size * _vcs; + _min_latency = -1; +} + +void BufferState::FeedbackSharedBufferPolicy::SetMinLatency(int min_latency) +{ +#ifdef DEBUG_FEEDBACK + cerr << FullName() << ": Setting minimum latency to " + << min_latency << "." << endl; +#endif + _min_latency = min_latency; +} + +void BufferState::FeedbackSharedBufferPolicy::SendingFlit(Flit const * const f) +{ + SharedBufferPolicy::SendingFlit(f); + _flit_sent_time[f->vc].push(GetSimTime()); +} + +int BufferState::FeedbackSharedBufferPolicy::_ComputeRTT(int vc, int last_rtt) const +{ + // compute moving average of round-trip time + int rtt = _round_trip_time[vc]; + if(rtt < 0) { + return last_rtt; + } + return ((rtt << _aging_scale) + last_rtt - rtt) >> _aging_scale; +} + +int BufferState::FeedbackSharedBufferPolicy::_ComputeLimit(int rtt) const +{ + // for every cycle that the measured average round trip time exceeded the + // observed minimum round trip time, reduce buffer occupancy limit by one + assert(_min_latency >= 0); + return max((_min_latency << 1) - rtt + _offset, 1); +} + +int BufferState::FeedbackSharedBufferPolicy::_ComputeMaxSlots(int vc) const +{ + int max_slots = _occupancy_limit[vc]; + if(!_flit_sent_time[vc].empty()) { + int min_rtt = GetSimTime() - _flit_sent_time[vc].front(); + int rtt = _ComputeRTT(vc, min_rtt); + int limit = _ComputeLimit(rtt); + max_slots = min(max_slots, limit); + } + return max_slots; +} + +void BufferState::FeedbackSharedBufferPolicy::FreeSlotFor(int vc) +{ + SharedBufferPolicy::FreeSlotFor(vc); + assert(!_flit_sent_time[vc].empty()); + int const last_rtt = GetSimTime() - _flit_sent_time[vc].front(); +#ifdef DEBUG_FEEDBACK + cerr << FullName() << ": Probe for VC " + << vc << " came back after " + << last_rtt << " cycles." + << endl; +#endif + _flit_sent_time[vc].pop(); + + int rtt = _ComputeRTT(vc, last_rtt); +#ifdef DEBUG_FEEDBACK + int old_rtt = _round_trip_time[vc]; + if(rtt != old_rtt) { + cerr << FullName() << ": Updating RTT estimate for VC " + << vc << " from " + << old_rtt << " to " + << rtt << " cycles." + << endl; + } +#endif + _round_trip_time[vc] = rtt; + + int limit = _ComputeLimit(rtt); +#ifdef DEBUG_FEEDBACK + int old_limit = _occupancy_limit[vc]; + int old_mapped_size = _total_mapped_size; +#endif + _total_mapped_size += (limit - _occupancy_limit[vc]); + _occupancy_limit[vc] = limit; +#ifdef DEBUG_FEEDBACK + if(limit != old_limit) { + cerr << FullName() << ": Occupancy limit for VC " + << vc << " changed from " + << old_limit << " to " + << limit << " slots." + << endl; + cerr << FullName() << ": Total mapped buffer space changed from " + << old_mapped_size << " to " + << _total_mapped_size << " slots." + << endl; + } +#endif +} + +bool BufferState::FeedbackSharedBufferPolicy::IsFullFor(int vc) const +{ + if(SharedBufferPolicy::IsFullFor(vc)) { + return true; + } + return (_buffer_state->OccupancyFor(vc) >= _ComputeMaxSlots(vc)); +} + +int BufferState::FeedbackSharedBufferPolicy::AvailableFor(int vc) const +{ + return min(SharedBufferPolicy::AvailableFor(vc), + _ComputeMaxSlots(vc) - _buffer_state->OccupancyFor(vc)); +} + +int BufferState::FeedbackSharedBufferPolicy::LimitFor(int vc) const +{ + return min(SharedBufferPolicy::LimitFor(vc), _ComputeMaxSlots(vc)); +} + +BufferState::SimpleFeedbackSharedBufferPolicy::SimpleFeedbackSharedBufferPolicy(Configuration const & config, BufferState * parent, const string & name) + : FeedbackSharedBufferPolicy(config, parent, name) +{ + _pending_credits.resize(_vcs, 0); +} + +void BufferState::SimpleFeedbackSharedBufferPolicy::SendingFlit(Flit const * const f) +{ + int const & vc = f->vc; + if(_flit_sent_time[vc].empty()) { + assert(_buffer_state->OccupancyFor(vc) > 0); + _pending_credits[vc] = _buffer_state->OccupancyFor(vc) - 1; +#ifdef DEBUG_SIMPLEFEEDBACK + cerr << FullName() << ": Sending probe flit for VC " + << vc << "; " + << _pending_credits[vc] << " non-probe flits in flight." + << endl; +#endif + FeedbackSharedBufferPolicy::SendingFlit(f); + return; + } + SharedBufferPolicy::SendingFlit(f); +} + +void BufferState::SimpleFeedbackSharedBufferPolicy::FreeSlotFor(int vc) +{ + if(!_flit_sent_time[vc].empty() && _pending_credits[vc] == 0) { +#ifdef DEBUG_SIMPLEFEEDBACK + cerr << FullName() << ": Probe credit for VC " + << vc << " came back." << endl; +#endif + FeedbackSharedBufferPolicy::FreeSlotFor(vc); + return; + } + if(_pending_credits[vc] > 0) { + assert(!_flit_sent_time[vc].empty()); + --_pending_credits[vc]; +#ifdef DEBUG_SIMPLEFEEDBACK + cerr << FullName() << ": Ignoring non-probe credit for VC " + << vc << "; " + << _pending_credits[vc] << " remaining." + << endl; +#endif + } + SharedBufferPolicy::FreeSlotFor(vc); +} + +BufferState::BufferState( const Configuration& config, Module *parent, const string& name ) : + Module( parent, name ), _occupancy(0) +{ + _vcs = config.GetInt( "num_vcs" ); + _size = config.GetInt("buf_size"); + if(_size < 0) { + _size = _vcs * config.GetInt("vc_buf_size"); + } + + _buffer_policy = BufferPolicy::New(config, this, "policy"); + + _wait_for_tail_credit = config.GetInt( "wait_for_tail_credit" ); + + _vc_occupancy.resize(_vcs, 0); + + _in_use_by.resize(_vcs, -1); + _tail_sent.resize(_vcs, false); + + _last_id.resize(_vcs, -1); + _last_pid.resize(_vcs, -1); + +#ifdef TRACK_BUFFERS + _classes = config.GetInt("classes"); + _outstanding_classes.resize(_vcs); + _class_occupancy.resize(_classes, 0); +#endif +} + +BufferState::~BufferState() +{ + delete _buffer_policy; +} + +void BufferState::ProcessCredit( Credit const * const c ) +{ + assert( c ); + + set<int>::iterator iter = c->vc.begin(); + while(iter != c->vc.end()) { + + int const vc = *iter; + + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + + if ( ( _wait_for_tail_credit ) && + ( _in_use_by[vc] < 0 ) ) { + ostringstream err; + err << "Received credit for idle VC " << vc; + Error( err.str() ); + } + --_occupancy; + if(_occupancy < 0) { + Error("Buffer occupancy fell below zero."); + } + --_vc_occupancy[vc]; + if(_vc_occupancy[vc] < 0) { + ostringstream err; + err << "Buffer occupancy fell below zero for VC " << vc; + Error(err.str()); + } + if(_wait_for_tail_credit && !_vc_occupancy[vc] && _tail_sent[vc]) { + assert(_in_use_by[vc] >= 0); + _in_use_by[vc] = -1; + } + +#ifdef TRACK_BUFFERS + assert(!_outstanding_classes[vc].empty()); + int cl = _outstanding_classes[vc].front(); + _outstanding_classes[vc].pop(); + assert((cl >= 0) && (cl < _classes)); + assert(_class_occupancy[cl] > 0); + --_class_occupancy[cl]; +#endif + + _buffer_policy->FreeSlotFor(vc); + + ++iter; + } +} + + +void BufferState::SendingFlit( Flit const * const f ) +{ + int const vc = f->vc; + + assert( f && ( vc >= 0 ) && ( vc < _vcs ) ); + + ++_occupancy; + if(_occupancy > _size) { + Error("Buffer overflow."); + } + + ++_vc_occupancy[vc]; + + _buffer_policy->SendingFlit(f); + +#ifdef TRACK_BUFFERS + _outstanding_classes[vc].push(f->cl); + ++_class_occupancy[f->cl]; +#endif + + if ( f->tail ) { + _tail_sent[vc] = true; + + if ( !_wait_for_tail_credit ) { + assert(_in_use_by[vc] >= 0); + _in_use_by[vc] = -1; + } + } + _last_id[vc] = f->id; + _last_pid[vc] = f->pid; +} + +void BufferState::TakeBuffer( int vc, int tag ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + + if ( _in_use_by[vc] >= 0 ) { + ostringstream err; + err << "Buffer taken while in use for VC " << vc; + Error( err.str() ); + } + _in_use_by[vc] = tag; + _tail_sent[vc] = false; + _buffer_policy->TakeBuffer(vc); +} + +void BufferState::Display( ostream & os ) const +{ + os << FullName() << " :" << endl; + os << " occupied = " << _occupancy << endl; + for ( int v = 0; v < _vcs; ++v ) { + os << " VC " << v << ": "; + os << "in_use_by = " << _in_use_by[v] + << ", tail_sent = " << _tail_sent[v] + << ", occupied = " << _vc_occupancy[v] << endl; + } +} diff --git a/src/intersim2/buffer_state.hpp b/src/intersim2/buffer_state.hpp new file mode 100644 index 0000000..32a7da1 --- /dev/null +++ b/src/intersim2/buffer_state.hpp @@ -0,0 +1,239 @@ +// $Id: buffer_state.hpp 5378 2013-01-10 03:40:11Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _BUFFER_STATE_HPP_ +#define _BUFFER_STATE_HPP_ + +#include <vector> +#include <queue> + +#include "module.hpp" +#include "flit.hpp" +#include "credit.hpp" +#include "config_utils.hpp" + +class BufferState : public Module { + + class BufferPolicy : public Module { + protected: + BufferState const * const _buffer_state; + public: + BufferPolicy(Configuration const & config, BufferState * parent, + const string & name); + virtual void SetMinLatency(int min_latency) {} + virtual void TakeBuffer(int vc = 0); + virtual void SendingFlit(Flit const * const f); + virtual void FreeSlotFor(int vc = 0); + virtual bool IsFullFor(int vc = 0) const = 0; + virtual int AvailableFor(int vc = 0) const = 0; + virtual int LimitFor(int vc = 0) const = 0; + + static BufferPolicy * New(Configuration const & config, + BufferState * parent, const string & name); + }; + + class PrivateBufferPolicy : public BufferPolicy { + protected: + int _vc_buf_size; + public: + PrivateBufferPolicy(Configuration const & config, BufferState * parent, + const string & name); + virtual void SendingFlit(Flit const * const f); + virtual bool IsFullFor(int vc = 0) const; + virtual int AvailableFor(int vc = 0) const; + virtual int LimitFor(int vc = 0) const; + }; + + class SharedBufferPolicy : public BufferPolicy { + protected: + int _buf_size; + vector<int> _private_buf_vc_map; + vector<int> _private_buf_size; + vector<int> _private_buf_occupancy; + int _shared_buf_size; + int _shared_buf_occupancy; + vector<int> _reserved_slots; + void ProcessFreeSlot(int vc = 0); + public: + SharedBufferPolicy(Configuration const & config, BufferState * parent, + const string & name); + virtual void SendingFlit(Flit const * const f); + virtual void FreeSlotFor(int vc = 0); + virtual bool IsFullFor(int vc = 0) const; + virtual int AvailableFor(int vc = 0) const; + virtual int LimitFor(int vc = 0) const; + }; + + class LimitedSharedBufferPolicy : public SharedBufferPolicy { + protected: + int _vcs; + int _active_vcs; + int _max_held_slots; + public: + LimitedSharedBufferPolicy(Configuration const & config, + BufferState * parent, + const string & name); + virtual void TakeBuffer(int vc = 0); + virtual void SendingFlit(Flit const * const f); + virtual bool IsFullFor(int vc = 0) const; + virtual int AvailableFor(int vc = 0) const; + virtual int LimitFor(int vc = 0) const; + }; + + class DynamicLimitedSharedBufferPolicy : public LimitedSharedBufferPolicy { + public: + DynamicLimitedSharedBufferPolicy(Configuration const & config, + BufferState * parent, + const string & name); + virtual void TakeBuffer(int vc = 0); + virtual void SendingFlit(Flit const * const f); + }; + + class ShiftingDynamicLimitedSharedBufferPolicy : public DynamicLimitedSharedBufferPolicy { + public: + ShiftingDynamicLimitedSharedBufferPolicy(Configuration const & config, + BufferState * parent, + const string & name); + virtual void TakeBuffer(int vc = 0); + virtual void SendingFlit(Flit const * const f); + }; + + class FeedbackSharedBufferPolicy : public SharedBufferPolicy { + protected: + int _ComputeRTT(int vc, int last_rtt) const; + int _ComputeLimit(int rtt) const; + int _ComputeMaxSlots(int vc) const; + int _vcs; + vector<int> _occupancy_limit; + vector<int> _round_trip_time; + vector<queue<int> > _flit_sent_time; + int _min_latency; + int _total_mapped_size; + int _aging_scale; + int _offset; + public: + FeedbackSharedBufferPolicy(Configuration const & config, + BufferState * parent, const string & name); + virtual void SetMinLatency(int min_latency); + virtual void SendingFlit(Flit const * const f); + virtual void FreeSlotFor(int vc = 0); + virtual bool IsFullFor(int vc = 0) const; + virtual int AvailableFor(int vc = 0) const; + virtual int LimitFor(int vc = 0) const; + }; + + class SimpleFeedbackSharedBufferPolicy : public FeedbackSharedBufferPolicy { + protected: + vector<int> _pending_credits; + public: + SimpleFeedbackSharedBufferPolicy(Configuration const & config, + BufferState * parent, const string & name); + virtual void SendingFlit(Flit const * const f); + virtual void FreeSlotFor(int vc = 0); + }; + + bool _wait_for_tail_credit; + int _size; + int _occupancy; + vector<int> _vc_occupancy; + int _vcs; + + BufferPolicy * _buffer_policy; + + vector<int> _in_use_by; + vector<bool> _tail_sent; + vector<int> _last_id; + vector<int> _last_pid; + +#ifdef TRACK_BUFFERS + int _classes; + vector<queue<int> > _outstanding_classes; + vector<int> _class_occupancy; +#endif + +public: + + BufferState( const Configuration& config, + Module *parent, const string& name ); + + ~BufferState(); + + inline void SetMinLatency(int min_latency) { + _buffer_policy->SetMinLatency(min_latency); + } + + void ProcessCredit( Credit const * const c ); + void SendingFlit( Flit const * const f ); + + void TakeBuffer( int vc = 0, int tag = 0 ); + + inline bool IsFull() const { + assert(_occupancy <= _size); + return (_occupancy == _size); + } + inline bool IsFullFor( int vc = 0 ) const { + return _buffer_policy->IsFullFor(vc); + } + inline int AvailableFor( int vc = 0 ) const { + return _buffer_policy->AvailableFor(vc); + } + inline int LimitFor( int vc = 0 ) const { + return _buffer_policy->LimitFor(vc); + } + inline bool IsEmptyFor(int vc = 0) const { + assert((vc >= 0) && (vc < _vcs)); + return (_vc_occupancy[vc] == 0); + } + inline bool IsAvailableFor( int vc = 0 ) const { + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _in_use_by[vc] < 0; + } + inline int UsedBy(int vc = 0) const { + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _in_use_by[vc]; + } + + inline int Occupancy() const { + return _occupancy; + } + + inline int OccupancyFor( int vc = 0 ) const { + assert((vc >= 0) && (vc < _vcs)); + return _vc_occupancy[vc]; + } + +#ifdef TRACK_BUFFERS + inline int OccupancyForClass(int c) const { + assert((c >= 0) && (c < _classes)); + return _class_occupancy[c]; + } +#endif + + void Display( ostream & os = cout ) const; +}; + +#endif diff --git a/src/intersim2/channel.hpp b/src/intersim2/channel.hpp new file mode 100644 index 0000000..13ad9f9 --- /dev/null +++ b/src/intersim2/channel.hpp @@ -0,0 +1,125 @@ +// $Id: channel.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +////////////////////////////////////////////////////////////////////// +// +// File Name: channel.hpp +// +// The Channel models a generic channel with a multi-cycle +// transmission delay. The channel latency can be specified as +// an integer number of simulator cycles. +// +///// +#ifndef _CHANNEL_HPP +#define _CHANNEL_HPP + +#include <queue> +#include <cassert> + +#include "globals.hpp" +#include "module.hpp" +#include "timed_module.hpp" + +using namespace std; + +template<typename T> +class Channel : public TimedModule { +public: + Channel(Module * parent, string const & name); + virtual ~Channel() {} + + // Physical Parameters + void SetLatency(int cycles); + int GetLatency() const { return _delay ; } + + // Send data + virtual void Send(T * data); + + // Receive data + virtual T * Receive(); + + virtual void ReadInputs(); + virtual void Evaluate() {} + virtual void WriteOutputs(); + +protected: + int _delay; + T * _input; + T * _output; + queue<pair<int, T *> > _wait_queue; + +}; + +template<typename T> +Channel<T>::Channel(Module * parent, string const & name) + : TimedModule(parent, name), _delay(1), _input(0), _output(0) { +} + +template<typename T> +void Channel<T>::SetLatency(int cycles) { + if(cycles <= 0) { + Error("Channel must have positive delay."); + } + _delay = cycles ; +} + +template<typename T> +void Channel<T>::Send(T * data) { + _input = data; +} + +template<typename T> +T * Channel<T>::Receive() { + return _output; +} + +template<typename T> +void Channel<T>::ReadInputs() { + if(_input) { + _wait_queue.push(make_pair(GetSimTime() + _delay - 1, _input)); + _input = 0; + } +} + +template<typename T> +void Channel<T>::WriteOutputs() { + _output = 0; + if(_wait_queue.empty()) { + return; + } + pair<int, T *> const & item = _wait_queue.front(); + int const & time = item.first; + if(GetSimTime() < time) { + return; + } + assert(GetSimTime() == time); + _output = item.second; + assert(_output); + _wait_queue.pop(); +} + +#endif diff --git a/src/intersim2/config.l b/src/intersim2/config.l new file mode 100644 index 0000000..4df14c7 --- /dev/null +++ b/src/intersim2/config.l @@ -0,0 +1,54 @@ +%{ + +#include "y.tab.h" + +static unsigned int lineno = 1; + +void config_error(char * msg, int lineno); +void yyerror(char * msg); + +extern int config_input(char *, int); +#undef YY_INPUT +#define YY_INPUT(b, r, ms) (r = config_input(b, ms)) + +%} + +Digit [0-9] +Exponent [eE][+-]?{Digit}+ +DblConst ({Digit}*\.)?{Digit}+{Exponent}? +StrConst [A-Za-z_\-/\.][A-Za-z0-9_\-/\.\+(\{\,)\}]* + +%% + + /* Ignore comments and all spaces */ + +\/\/[^\n]* ; +[ \t\r]* ; + +\n { lineno++; } + + /* Commands */ + +\{[A-Za-z0-9_\-\.(\{\,)\}]+(\,[A-Za-z0-9_\-\.(\{\,)\}]+)*\} { yylval.name = strdup( yytext ); return STR; } + +-?[0-9]+ { yylval.num = atoi( yytext ); return NUM; } + +-?[0-9]*\.[0-9]+ { yylval.fnum = atof( yytext ); return FNUM; } + +-?{DblConst} { yylval.fnum = atof( yytext ); return FNUM;} + +{StrConst} { yylval.name = strdup( yytext ); return STR; } + +. { return yytext[0]; } + +%% + +void yyerror( char * msg ) +{ + config_error( msg, lineno ); +} + +int yywrap() +{ + return 1; +} diff --git a/src/intersim2/config.y b/src/intersim2/config.y new file mode 100644 index 0000000..377d467 --- /dev/null +++ b/src/intersim2/config.y @@ -0,0 +1,37 @@ +%{ + +int yylex(void); +void yyerror(char * msg); +void config_assign_string( char const * field, char const * value ); +void config_assign_int( char const * field, int value ); +void config_assign_float( char const * field, double value ); + +#ifdef _WIN32 +#pragma warning ( disable : 4102 ) +#pragma warning ( disable : 4244 ) +#endif + +%} + +%union { + char *name; + int num; + double fnum; +} + +%token <name> STR +%token <num> NUM +%token <fnum> FNUM + +%% + +commands : commands command + | command +; + +command : STR '=' STR ';' { config_assign_string( $1, $3 ); free( $1 ); free( $3 ); } + | STR '=' NUM ';' { config_assign_int( $1, $3 ); free( $1 ); } + | STR '=' FNUM ';' { config_assign_float( $1, $3 ); free( $1 ); } +; + +%% diff --git a/src/intersim2/config_utils.cpp b/src/intersim2/config_utils.cpp new file mode 100644 index 0000000..fad5fce --- /dev/null +++ b/src/intersim2/config_utils.cpp @@ -0,0 +1,447 @@ +// $Id: config_utils.cpp 5188 2012-08-30 00:31:31Z dub $ +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*config_utils.cpp + * + *The configuration object which contained the parsed data from the + *configuration file + */ + +#include "booksim.hpp" +#include <iostream> +#include <cstring> +#include <sstream> +#include <fstream> +#include <cstdlib> + +#include "config_utils.hpp" + +Configuration *Configuration::theConfig = 0; + +Configuration::Configuration() +{ + theConfig = this; + _config_file = 0; +} + +void Configuration::AddStrField(string const & field, string const & value) +{ + _str_map[field] = value; +} + +void Configuration::Assign(string const & field, string const & value) +{ + map<string, string>::const_iterator match; + + match = _str_map.find(field); + if(match != _str_map.end()) { + _str_map[field] = value; + } else { + ParseError("Unknown string field: " + field); + } +} + +void Configuration::Assign(string const & field, int value) +{ + map<string, int>::const_iterator match; + + match = _int_map.find(field); + if(match != _int_map.end()) { + _int_map[field] = value; + } else { + ParseError("Unknown integer field: " + field); + } +} + +void Configuration::Assign(string const & field, double value) +{ + map<string, double>::const_iterator match; + + match = _float_map.find(field); + if(match != _float_map.end()) { + _float_map[field] = value; + } else { + ParseError("Unknown double field: " + field); + } +} + +string Configuration::GetStr(string const & field) const +{ + map<string, string>::const_iterator match; + + match = _str_map.find(field); + if(match != _str_map.end()) { + return match->second; + } else { + ParseError("Unknown string field: " + field); + exit(-1); + } +} + +int Configuration::GetInt(string const & field) const +{ + map<string, int>::const_iterator match; + + match = _int_map.find(field); + if(match != _int_map.end()) { + return match->second; + } else { + ParseError("Unknown integer field: " + field); + exit(-1); + } +} + +double Configuration::GetFloat(string const & field) const +{ + map<string,double>::const_iterator match; + + match = _float_map.find(field); + if(match != _float_map.end()) { + return match->second; + } else { + ParseError("Unknown double field: " + field); + exit(-1); + } +} + +vector<string> Configuration::GetStrArray(string const & field) const +{ + string const param_str = GetStr(field); + return tokenize_str(param_str); +} + +vector<int> Configuration::GetIntArray(string const & field) const +{ + string const param_str = GetStr(field); + return tokenize_int(param_str); +} + +vector<double> Configuration::GetFloatArray(string const & field) const +{ + string const param_str = GetStr(field); + return tokenize_float(param_str); +} + +void Configuration::ParseFile(string const & filename) +{ + if((_config_file = fopen(filename.c_str(), "r")) == 0) { + cerr << "Could not open configuration file " << filename << endl; + exit(-1); + } + + yyparse(); + + fclose(_config_file); + _config_file = 0; +} + +void Configuration::ParseString(string const & str) +{ + _config_string = str + ';'; + yyparse(); + _config_string = ""; +} + +int Configuration::Input(char * line, int max_size) +{ + int length = 0; + + if(_config_file) { + length = fread(line, 1, max_size, _config_file); + } else { + length = _config_string.length(); + _config_string.copy(line, max_size); + _config_string.clear(); + } + + return length; +} + +void Configuration::ParseError(string const & msg, unsigned int lineno) const +{ + if(lineno) { + cerr << "Parse error on line " << lineno << " : " << msg << endl; + } else { + cerr << "Parse error : " << msg << endl; + } + + + exit( -1 ); +} + +Configuration * Configuration::GetTheConfig() +{ + return theConfig; +} + +//============================================================ + +extern "C" void config_error( char const * msg, int lineno ) +{ + Configuration::GetTheConfig( )->ParseError( msg, lineno ); +} + +extern "C" void config_assign_string( char const * field, char const * value ) +{ + Configuration::GetTheConfig()->Assign(field, value); +} + +extern "C" void config_assign_int( char const * field, int value ) +{ + Configuration::GetTheConfig()->Assign(field, value); +} + +extern "C" void config_assign_float( char const * field, double value ) +{ + Configuration::GetTheConfig()->Assign(field, value); +} + +extern "C" int config_input(char * line, int max_size) +{ + return Configuration::GetTheConfig()->Input(line, max_size); +} + +bool ParseArgs(Configuration * cf, int argc, char * * argv) +{ + bool rc = false; + + //all dashed variables are ignored by the arg parser + for(int i = 1; i < argc; ++i) { + string arg(argv[i]); + size_t pos = arg.find('='); + bool dash = (argv[i][0] =='-'); + if(pos == string::npos && !dash) { + // parse config file + cf->ParseFile( argv[i] ); + ifstream in(argv[i]); + cout << "BEGIN Configuration File: " << argv[i] << endl; + while (!in.eof()) { + char c; + in.get(c); + cout << c ; + } + cout << "END Configuration File: " << argv[i] << endl; + rc = true; + } else if(pos != string::npos) { + // override individual parameter + cout << "OVERRIDE Parameter: " << arg << endl; + cf->ParseString(argv[i]); + } + } + + return rc; +} + + +//helpful for the GUI, write out nearly all variables contained in a config file. +//However, it can't and won't write out empty strings since the booksim yacc +//parser won't be abled to parse blank strings +void Configuration::WriteFile(string const & filename) { + + ostream *config_out= new ofstream(filename.c_str()); + + + for(map<string,string>::const_iterator i = _str_map.begin(); + i!=_str_map.end(); + i++){ + //the parser won't read empty strings + if(i->second[0]!='\0'){ + *config_out<<i->first<<" = "<<i->second<<";"<<endl; + } + } + + for(map<string, int>::const_iterator i = _int_map.begin(); + i!=_int_map.end(); + i++){ + *config_out<<i->first<<" = "<<i->second<<";"<<endl; + + } + + for(map<string, double>::const_iterator i = _float_map.begin(); + i!=_float_map.end(); + i++){ + *config_out<<i->first<<" = "<<i->second<<";"<<endl; + + } + config_out->flush(); + delete config_out; + +} + + + +void Configuration::WriteMatlabFile(ostream * config_out) const { + + + + for(map<string,string>::const_iterator i = _str_map.begin(); + i!=_str_map.end(); + i++){ + //the parser won't read blanks lolz + if(i->second[0]!='\0'){ + *config_out<<"%"<<i->first<<" = \'"<<i->second<<"\';"<<endl; + } + } + + for(map<string, int>::const_iterator i = _int_map.begin(); + i!=_int_map.end(); + i++){ + *config_out<<"%"<<i->first<<" = "<<i->second<<";"<<endl; + + } + + for(map<string, double>::const_iterator i = _float_map.begin(); + i!=_float_map.end(); + i++){ + *config_out<<"%"<<i->first<<" = "<<i->second<<";"<<endl; + + } + config_out->flush(); + +} + +vector<string> tokenize_str(string const & data) +{ + vector<string> values; + + // no elements, no braces --> empty list + if(data.empty()) { + return values; + } + + // doesn't start with an opening brace --> treat as single element + // note that this element can potentially contain nested lists + if(data[0] != '{') { + values.push_back(data); + return values; + } + + size_t start = 1; + int nested = 0; + + size_t curr = start; + + while(string::npos != (curr = data.find_first_of("{,}", curr))) { + + if(data[curr] == '{') { + ++nested; + } else if((data[curr] == '}') && nested) { + --nested; + } else if(!nested) { + if(curr > start) { + string token = data.substr(start, curr - start); + values.push_back(token); + } + start = curr + 1; + } + ++curr; + } + assert(!nested); + + return values; +} + +vector<int> tokenize_int(string const & data) +{ + vector<int> values; + + // no elements, no braces --> empty list + if(data.empty()) { + return values; + } + + // doesn't start with an opening brace --> treat as single element + // note that this element can potentially contain nested lists + if(data[0] != '{') { + values.push_back(atoi(data.c_str())); + return values; + } + + size_t start = 1; + int nested = 0; + + size_t curr = start; + + while(string::npos != (curr = data.find_first_of("{,}", curr))) { + + if(data[curr] == '{') { + ++nested; + } else if((data[curr] == '}') && nested) { + --nested; + } else if(!nested) { + if(curr > start) { + string token = data.substr(start, curr - start); + values.push_back(atoi(token.c_str())); + } + start = curr + 1; + } + ++curr; + } + assert(!nested); + + return values; +} + +vector<double> tokenize_float(string const & data) +{ + vector<double> values; + + // no elements, no braces --> empty list + if(data.empty()) { + return values; + } + + // doesn't start with an opening brace --> treat as single element + // note that this element can potentially contain nested lists + if(data[0] != '{') { + values.push_back(atof(data.c_str())); + return values; + } + + size_t start = 1; + int nested = 0; + + size_t curr = start; + + while(string::npos != (curr = data.find_first_of("{,}", curr))) { + + if(data[curr] == '{') { + ++nested; + } else if((data[curr] == '}') && nested) { + --nested; + } else if(!nested) { + if(curr > start) { + string token = data.substr(start, curr - start); + values.push_back(atof(token.c_str())); + } + start = curr + 1; + } + ++curr; + } + assert(!nested); + + return values; +} diff --git a/src/intersim2/config_utils.hpp b/src/intersim2/config_utils.hpp new file mode 100644 index 0000000..de3343b --- /dev/null +++ b/src/intersim2/config_utils.hpp @@ -0,0 +1,95 @@ +// $Id: config_utils.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _CONFIG_UTILS_HPP_ +#define _CONFIG_UTILS_HPP_ + +#include "booksim.hpp" + +#include<cstdio> +#include<string> +#include<map> +#include<vector> + +extern "C" int yyparse(); + +class Configuration { + static Configuration * theConfig; + FILE * _config_file; + string _config_string; + +protected: + map<string,string> _str_map; + map<string,int> _int_map; + map<string,double> _float_map; + +public: + Configuration(); + + void AddStrField(string const & field, string const & value); + + void Assign(string const & field, string const & value); + void Assign(string const & field, int value); + void Assign(string const & field, double value); + + string GetStr(string const & field) const; + int GetInt(string const & field) const; + double GetFloat(string const & field) const; + + vector<string> GetStrArray(const string & field) const; + vector<int> GetIntArray(const string & field) const; + vector<double> GetFloatArray(const string & field) const; + + void ParseFile(string const & filename); + void ParseString(string const & str); + int Input(char * line, int max_size); + void ParseError(string const & msg, unsigned int lineno = 0) const; + + void WriteFile(string const & filename); + void WriteMatlabFile(ostream * o) const; + + inline const map<string, string> & GetStrMap() const { + return _str_map; + } + inline const map<string, int> & GetIntMap() const { + return _int_map; + } + inline const map<string, double> & GetFloatMap() const { + return _float_map; + } + + static Configuration * GetTheConfig(); + +}; + +bool ParseArgs(Configuration * cf, int argc, char **argv); + +vector<string> tokenize_str(string const & data); +vector<int> tokenize_int(string const & data); +vector<double> tokenize_float(string const & data); + +#endif diff --git a/src/intersim2/credit.cpp b/src/intersim2/credit.cpp new file mode 100644 index 0000000..c6db498 --- /dev/null +++ b/src/intersim2/credit.cpp @@ -0,0 +1,79 @@ +// $Id: credit.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*credit.cpp + * + *A class for credits + */ + +#include "booksim.hpp" +#include "credit.hpp" + +stack<Credit *> Credit::_all; +stack<Credit *> Credit::_free; + +Credit::Credit() +{ + Reset(); +} + +void Credit::Reset() +{ + vc.clear(); + head = false; + tail = false; + id = -1; +} + +Credit * Credit::New() { + Credit * c; + if(_free.empty()) { + c = new Credit(); + _all.push(c); + } else { + c = _free.top(); + c->Reset(); + _free.pop(); + } + return c; +} + +void Credit::Free() { + _free.push(this); +} + +void Credit::FreeAll() { + while(!_all.empty()) { + delete _all.top(); + _all.pop(); + } +} + + +int Credit::OutStanding(){ + return _all.size()-_free.size(); +} diff --git a/src/intersim2/credit.hpp b/src/intersim2/credit.hpp new file mode 100644 index 0000000..8081394 --- /dev/null +++ b/src/intersim2/credit.hpp @@ -0,0 +1,60 @@ +// $Id: credit.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _CREDIT_HPP_ +#define _CREDIT_HPP_ + +#include <set> +#include <stack> + +class Credit { + +public: + + set<int> vc; + + // these are only used by the event router + bool head, tail; + int id; + + void Reset(); + + static Credit * New(); + void Free(); + static void FreeAll(); + static int OutStanding(); +private: + + static stack<Credit *> _all; + static stack<Credit *> _free; + + Credit(); + ~Credit() {} + +}; + +#endif diff --git a/src/intersim2/examples/cmeshconfig b/src/intersim2/examples/cmeshconfig new file mode 100644 index 0000000..c71ff8d --- /dev/null +++ b/src/intersim2/examples/cmeshconfig @@ -0,0 +1,47 @@ +// $Id: cmeshconfig 5188 2012-08-30 00:31:31Z dub $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +//concentrated mesh configuration file running batch mode +//xr, yr, x, y, are use to indicate how the concnetration is formed. + +topology = cmesh; + +k = 4; +n = 2; +c = 4; +xr = 2; +yr = 2; + +x = 4; +y = 4; + +routing_function = dor_no_express; + +traffic = bitcomp; + +use_read_write = 0; + +batch_size = 2000; diff --git a/src/intersim2/examples/dragonflyconfig b/src/intersim2/examples/dragonflyconfig new file mode 100644 index 0000000..763b549 --- /dev/null +++ b/src/intersim2/examples/dragonflyconfig @@ -0,0 +1,79 @@ +// $Id: dragonflyconfig 5188 2012-08-30 00:31:31Z dub $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +// Dragonfly +// + + + + +vc_buf_size = 256; + + +wait_for_tail_credit = 0; + +// +// Router architecture +// +vc_allocator = separable_input_first; +sw_allocator = separable_input_first; +alloc_iters = 1; + +credit_delay = 2; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; +st_final_delay = 1; + +input_speedup = 1; +output_speedup = 1; +internal_speedup = 2.0; + + +warmup_periods = 3; +sim_count = 1; + +sample_period = 10000; + + + +routing_function = min; +num_vcs = 2; + +priority = none; +traffic = uniform; + +injection_rate = 0.8; +packet_size = 10; +injection_rate_uses_flits=1; + +topology = dragonflynew; + +k = 4; +n = 1; + +watch_out=-; + diff --git a/src/intersim2/examples/fattree_config b/src/intersim2/examples/fattree_config new file mode 100644 index 0000000..b4202ff --- /dev/null +++ b/src/intersim2/examples/fattree_config @@ -0,0 +1,76 @@ +// $Id: dragonflyconfig 3555 2011-05-16 23:37:55Z dub $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + + +hold_switch_for_packet=1; + +vc_buf_size = 16; + + +wait_for_tail_credit = 0; + +// +// Router architecture +// +vc_allocator = separable_input_first; +sw_allocator = separable_input_first; +alloc_iters = 1; + +credit_delay = 2; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; +st_final_delay = 1; + +input_speedup = 1; +output_speedup = 1; +internal_speedup = 1.0; + + +warmup_periods = 3; +sim_count = 1; + +sample_period = 10000; + + + +routing_function = nca; +num_vcs = 4; + +priority = none; +traffic = uniform; + +injection_rate = 0.6; +packet_size = 1; +injection_rate_uses_flits=1; + +topology = fattree; + + +k = 4; +n = 3; + +watch_out=-;
\ No newline at end of file diff --git a/src/intersim2/examples/flatflyconfig b/src/intersim2/examples/flatflyconfig new file mode 100644 index 0000000..6674d28 --- /dev/null +++ b/src/intersim2/examples/flatflyconfig @@ -0,0 +1,116 @@ +// $Id: flatflyconfig 5188 2012-08-30 00:31:31Z dub $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +//A flattened butterfly configurate file with many tweaks from the +//default settings. + + +// Flow control +// Total number of VCs must match the above assignments +num_vcs = 8; +vc_buf_size = 4; + +wait_for_tail_credit = 0; + +// +// Router architectureq +// +vc_allocator = islip; +sw_allocator = islip; +alloc_iters = 1; + +credit_delay = 2; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; +st_final_delay = 1; + +input_speedup = 1; +output_speedup = 1; +internal_speedup = 1.0; + +// +// Traffic +// + +warmup_periods = 3; + +sample_period = 1000; + +sim_count = 1; + +traffic = uniform; + + +// Flatfly +// +// #node = k^(n+1) +// +// x, y, specifies the arrangement of routers in x and y dim +// xr, yr specifiies the arayment of clients in a router +// +topology = flatfly; +subnets = 1; + +c = 4; +k = 4; +n = 2; + +x = 4; +y = 4; +xr = 2; +yr = 2; + +// +// Routing +// + +routing_function = ran_min; + +//1: batch mode, 0: injection mode +use_read_write = 0; + +//for injection mode +packet_size = 1; +injection_rate = 0.1; + +//for batch mode +read_request_size=1; +write_request_size=1; +read_reply_size=1; +write_reply_size=1; + +read_request_begin_vc = 0; +read_request_end_vc = 3; +write_reply_begin_vc = 4; +write_reply_end_vc = 7; +read_reply_begin_vc = 4; +read_reply_end_vc = 7; +write_request_begin_vc = 0; +write_request_end_vc = 3; + +//latency: drains all packet, throughput:no drain? +sim_type = latency; diff --git a/src/intersim2/examples/mesh88_lat b/src/intersim2/examples/mesh88_lat new file mode 100644 index 0000000..189104e --- /dev/null +++ b/src/intersim2/examples/mesh88_lat @@ -0,0 +1,69 @@ +// $Id: mesh88_lat 5506 2013-05-07 21:22:23Z qtedq $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +//8X8 mesh with 20 flits per packet under injection mode +//injection rate here is packet per cycle, NOT flit per cycle + +// Topology + +topology = mesh; +k = 8; +n = 2; + +// Routing +routing_function = dor; + +// Flow control +num_vcs = 8; +vc_buf_size = 8; +wait_for_tail_credit = 1; + +// Router architecture +vc_allocator = islip; +sw_allocator = islip; +alloc_iters = 1; + +credit_delay = 2; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; + +input_speedup = 2; +output_speedup = 1; +internal_speedup = 1.0; + + +// Traffic +traffic = transpose; +packet_size = 20; + + +// Simulation +sim_type = latency; + +injection_rate = 0.005; +watch_packets = {1,1,1}; + diff --git a/src/intersim2/examples/mesh88_lat_hotspot b/src/intersim2/examples/mesh88_lat_hotspot new file mode 100644 index 0000000..45c2b3f --- /dev/null +++ b/src/intersim2/examples/mesh88_lat_hotspot @@ -0,0 +1,82 @@ +// $Id: mesh88_lat 5487 2013-02-27 08:16:18Z qtedq $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +//8X8 mesh with 20 flits per packet under injection mode +//injection rate here is packet per cycle, NOT flit per cycle + +// Topology + +topology = mesh; +k = 8; +n = 2; + +// Routing + +routing_function = dor; + +// Flow control + +num_vcs = 8; +vc_buf_size = 8; + +wait_for_tail_credit = 0; + +// Router architecture + +vc_allocator = separable_input_first; +sw_allocator = separable_input_first; +alloc_iters = 1; + +credit_delay = 2; +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; +speculative=1; + +input_speedup = 1; +output_speedup = 1; +internal_speedup = 1.0; + +// Traffic + +traffic = hotspot; +packet_size ={{1,2,3,4},{10,20}}; +packet_size_rate={{1,1,1,1},{2,1}}; +// Simulation + +sim_type = latency; +latency_thres = 100000.0; + +injection_rate = 0.1; + + +classes=2; + + +classes=2; +injection_rate={0.01,0.01}; +packet_size={{1,5},{10,20}}; +packet_size_rate={{1,1},{2,1}}; diff --git a/src/intersim2/examples/singleconfig b/src/intersim2/examples/singleconfig new file mode 100644 index 0000000..aca3d28 --- /dev/null +++ b/src/intersim2/examples/singleconfig @@ -0,0 +1,57 @@ +// $Id: singleconfig 5188 2012-08-30 00:31:31Z dub $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +//A single cross 10X10 cross bar under injection mode + +topology = fly; + +k = 10; +n = 1; + +num_vcs = 8; + +vc_buf_size = 8; + +vc_allocator = separable_input_first; +sw_allocator = separable_input_first; + +routing_function = dest_tag; + +traffic = uniform; + +use_read_write = 0; + +injection_rate = 1.0; + + + + +sample_period = 100000; + +routing_delay = 0; +vc_alloc_delay = 1; +sw_alloc_delay = 1; +st_final_delay = 1; diff --git a/src/intersim2/examples/torus88 b/src/intersim2/examples/torus88 new file mode 100644 index 0000000..17ae91f --- /dev/null +++ b/src/intersim2/examples/torus88 @@ -0,0 +1,40 @@ +// $Id: torus88 5188 2012-08-30 00:31:31Z dub $ + +// Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 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 THE COPYRIGHT OWNER 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. + +//simple 8X8 torus under injection mode + + +// Topology +topology = torus; +k = 8; +n = 2; +// Routing +routing_function = dim_order; +// Flow control +num_vcs = 2; +// Traffic +traffic = uniform; +injection_rate = 0.15; diff --git a/src/intersim2/flit.cpp b/src/intersim2/flit.cpp new file mode 100644 index 0000000..8e0c66f --- /dev/null +++ b/src/intersim2/flit.cpp @@ -0,0 +1,107 @@ +// $Id: flit.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*flit.cpp + * + *flit struct is a flit, carries all the control signals that a flit needs + *Add additional signals as necessary. Flits has no concept of length + *it is a singluar object. + * + *When adding objects make sure to set a default value in this constructor + */ + +#include "booksim.hpp" +#include "flit.hpp" + +stack<Flit *> Flit::_all; +stack<Flit *> Flit::_free; + +ostream& operator<<( ostream& os, const Flit& f ) +{ + os << " Flit ID: " << f.id << " (" << &f << ")" + << " Packet ID: " << f.pid + << " Type: " << f.type + << " Head: " << f.head + << " Tail: " << f.tail << endl; + os << " Source: " << f.src << " Dest: " << f.dest << " Intm: "<<f.intm<<endl; + os << " Creation time: " << f.ctime << " Injection time: " << f.itime << " Arrival time: " << f.atime << " Phase: "<<f.ph<< endl; + os << " VC: " << f.vc << endl; + return os; +} + +Flit::Flit() +{ + Reset(); +} + +void Flit::Reset() +{ + type = ANY_TYPE ; + vc = -1 ; + cl = -1 ; + head = false ; + tail = false ; + ctime = -1 ; + itime = -1 ; + atime = -1 ; + id = -1 ; + pid = -1 ; + hops = 0 ; + watch = false ; + record = false ; + intm = 0; + src = -1; + dest = -1; + pri = 0; + intm =-1; + ph = -1; + data = 0; +} + +Flit * Flit::New() { + Flit * f; + if(_free.empty()) { + f = new Flit; + _all.push(f); + } else { + f = _free.top(); + f->Reset(); + _free.pop(); + } + return f; +} + +void Flit::Free() { + _free.push(this); +} + +void Flit::FreeAll() { + while(!_all.empty()) { + delete _all.top(); + _all.pop(); + } +} diff --git a/src/intersim2/flit.hpp b/src/intersim2/flit.hpp new file mode 100644 index 0000000..fd48306 --- /dev/null +++ b/src/intersim2/flit.hpp @@ -0,0 +1,104 @@ +// $Id: flit.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _FLIT_HPP_ +#define _FLIT_HPP_ + +#include <iostream> +#include <stack> + +#include "booksim.hpp" +#include "outputset.hpp" + +class Flit { + +public: + + const static int NUM_FLIT_TYPES = 5; + enum FlitType { READ_REQUEST = 0, + READ_REPLY = 1, + WRITE_REQUEST = 2, + WRITE_REPLY = 3, + ANY_TYPE = 4 }; + FlitType type; + + int vc; + + int cl; + + bool head; + bool tail; + + int ctime; + int itime; + int atime; + + int id; + int pid; + + bool record; + + int src; + int dest; + + int pri; + + int hops; + bool watch; + int subnetwork; + + // intermediate destination (if any) + mutable int intm; + + // phase in multi-phase algorithms + mutable int ph; + + // Fields for arbitrary data + void* data ; + + // Lookahead route info + OutputSet la_route_set; + + void Reset(); + + static Flit * New(); + void Free(); + static void FreeAll(); + +private: + + Flit(); + ~Flit() {} + + static stack<Flit *> _all; + static stack<Flit *> _free; + +}; + +ostream& operator<<( ostream& os, const Flit& f ); + +#endif diff --git a/src/intersim2/flitchannel.cpp b/src/intersim2/flitchannel.cpp new file mode 100644 index 0000000..0515f5f --- /dev/null +++ b/src/intersim2/flitchannel.cpp @@ -0,0 +1,91 @@ +// $Id: flitchannel.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// File Name: flitchannel.cpp +// Author: James Balfour, Rebecca Schultz +// +// ---------------------------------------------------------------------- + +#include "flitchannel.hpp" + +#include <iostream> +#include <iomanip> + +#include "router.hpp" +#include "globals.hpp" + +// ---------------------------------------------------------------------- +// $Author: jbalfour $ +// $Date: 2007/06/27 23:10:17 $ +// $Id: flitchannel.cpp 5188 2012-08-30 00:31:31Z dub $ +// ---------------------------------------------------------------------- +FlitChannel::FlitChannel(Module * parent, string const & name, int classes) +: Channel<Flit>(parent, name), _routerSource(NULL), _routerSourcePort(-1), + _routerSink(NULL), _routerSinkPort(-1), _idle(0), _classes(classes) { + _active.resize(classes, 0); +} + +void FlitChannel::SetSource(Router const * const router, int port) { + _routerSource = router; + _routerSourcePort = port; +} + +void FlitChannel::SetSink(Router const * const router, int port) { + _routerSink = router; + _routerSinkPort = port; +} + +void FlitChannel::Send(Flit * f) { + if(f) { + ++_active[f->cl]; + } else { + ++_idle; + } + Channel<Flit>::Send(f); +} + +void FlitChannel::ReadInputs() { + Flit const * const & f = _input; + if(f && f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Beginning channel traversal for flit " << f->id + << " with delay " << _delay + << "." << endl; + } + Channel<Flit>::ReadInputs(); +} + +void FlitChannel::WriteOutputs() { + Channel<Flit>::WriteOutputs(); + if(_output && _output->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Completed channel traversal for flit " << _output->id + << "." << endl; + } +} diff --git a/src/intersim2/flitchannel.hpp b/src/intersim2/flitchannel.hpp new file mode 100644 index 0000000..632ab10 --- /dev/null +++ b/src/intersim2/flitchannel.hpp @@ -0,0 +1,100 @@ +// $Id: flitchannel.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// File Name: flitchannel.hpp +// +// The FlitChannel models a flit channel with a multi-cycle +// transmission delay. The channel latency can be specified as +// an integer number of simulator cycles. +// ---------------------------------------------------------------------- + +#ifndef FLITCHANNEL_HPP +#define FLITCHANNEL_HPP + +// ---------------------------------------------------------------------- +// $Author: jbalfour $ +// $Date: 2007/06/27 23:10:17 $ +// $Id: flitchannel.hpp 5188 2012-08-30 00:31:31Z dub $ +// ---------------------------------------------------------------------- + +#include "channel.hpp" +#include "flit.hpp" + +using namespace std; + +class Router ; + +class FlitChannel : public Channel<Flit> { +public: + FlitChannel(Module * parent, string const & name, int classes); + + void SetSource(Router const * const router, int port) ; + inline Router const * const GetSource() const { + return _routerSource; + } + inline int const & GetSourcePort() const { + return _routerSourcePort; + } + void SetSink(Router const * const router, int port) ; + inline Router const * const GetSink() const { + return _routerSink; + } + inline int const & GetSinkPort() const { + return _routerSinkPort; + } + inline vector<int> const & GetActivity() const { + return _active; + } + + // Send flit + virtual void Send(Flit * flit); + + virtual void ReadInputs(); + virtual void WriteOutputs(); + +private: + + //////////////////////////////////////// + // + // Power Models OBSOLETE + // + //////////////////////////////////////// + + Router const * _routerSource; + int _routerSourcePort; + Router const * _routerSink; + int _routerSinkPort; + + // Statistics for Activity Factors + vector<int> _active; + int _idle; + int _classes; +}; + +#endif diff --git a/src/intersim2/globals.hpp b/src/intersim2/globals.hpp new file mode 100644 index 0000000..c443512 --- /dev/null +++ b/src/intersim2/globals.hpp @@ -0,0 +1,56 @@ +// $Id: globals.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _GLOBALS_HPP_ +#define _GLOBALS_HPP_ +#include <string> +#include <vector> +#include <iostream> + +/*all declared in main.cpp*/ + +int GetSimTime(); + +class Stats; +Stats * GetStats(const std::string & name); + +class InterconnectInterface; +extern InterconnectInterface *g_icnt_interface; + +extern bool gPrintActivity; + +extern int gK; +extern int gN; +extern int gC; + +extern int gNodes; + +extern bool gTrace; + +extern std::ostream * gWatchOut; + +#endif diff --git a/src/intersim2/gputrafficmanager.cpp b/src/intersim2/gputrafficmanager.cpp new file mode 100644 index 0000000..bf422d6 --- /dev/null +++ b/src/intersim2/gputrafficmanager.cpp @@ -0,0 +1,676 @@ +// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda +// The University of British Columbia +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of The University of British Columbia 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 THE COPYRIGHT HOLDER 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. + +#include <sstream> +#include <fstream> +#include <limits> + +#include "gputrafficmanager.hpp" +#include "interconnect_interface.hpp" +#include "globals.hpp" + + +GPUTrafficManager::GPUTrafficManager( const Configuration &config, const vector<Network *> &net) +:TrafficManager(config, net) +{ + // The total simulations equal to number of kernels + _total_sims = 0; + + _input_queue.resize(_subnets); + for ( int subnet = 0; subnet < _subnets; ++subnet) { + _input_queue[subnet].resize(_nodes); + for ( int node = 0; node < _nodes; ++node ) { + _input_queue[subnet][node].resize(_classes); + } + } +} + +GPUTrafficManager::~GPUTrafficManager() +{ +} + +void GPUTrafficManager::Init() +{ + _time = 0; + _sim_state = running; + _ClearStats( ); + +} + +void GPUTrafficManager::_RetireFlit( Flit *f, int dest ) +{ + _deadlock_timer = 0; + + assert(_total_in_flight_flits[f->cl].count(f->id) > 0); + _total_in_flight_flits[f->cl].erase(f->id); + + if(f->record) { + assert(_measured_in_flight_flits[f->cl].count(f->id) > 0); + _measured_in_flight_flits[f->cl].erase(f->id); + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << dest << " | " + << "Retiring flit " << f->id + << " (packet " << f->pid + << ", src = " << f->src + << ", dest = " << f->dest + << ", hops = " << f->hops + << ", flat = " << f->atime - f->itime + << ")." << endl; + } + + if ( f->head && ( f->dest != dest ) ) { + ostringstream err; + err << "Flit " << f->id << " arrived at incorrect output " << dest; + Error( err.str( ) ); + } + + if((_slowest_flit[f->cl] < 0) || + (_flat_stats[f->cl]->Max() < (f->atime - f->itime))) + _slowest_flit[f->cl] = f->id; + + _flat_stats[f->cl]->AddSample( f->atime - f->itime); + if(_pair_stats){ + _pair_flat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - f->itime ); + } + + if ( f->tail ) { + Flit * head; + if(f->head) { + head = f; + } else { + map<int, Flit *>::iterator iter = _retired_packets[f->cl].find(f->pid); + assert(iter != _retired_packets[f->cl].end()); + head = iter->second; + _retired_packets[f->cl].erase(iter); + assert(head->head); + assert(f->pid == head->pid); + } + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << dest << " | " + << "Retiring packet " << f->pid + << " (plat = " << f->atime - head->ctime + << ", nlat = " << f->atime - head->itime + << ", frag = " << (f->atime - head->atime) - (f->id - head->id) // NB: In the spirit of solving problems using ugly hacks, we compute the packet length by taking advantage of the fact that the IDs of flits within a packet are contiguous. + << ", src = " << head->src + << ", dest = " << head->dest + << ")." << endl; + } + +// GPGPUSim: Memory will handle reply, do not need this +#if 0 + //code the source of request, look carefully, its tricky ;) + if (f->type == Flit::READ_REQUEST || f->type == Flit::WRITE_REQUEST) { + PacketReplyInfo* rinfo = PacketReplyInfo::New(); + rinfo->source = f->src; + rinfo->time = f->atime; + rinfo->record = f->record; + rinfo->type = f->type; + _repliesPending[dest].push_back(rinfo); + } else { + if(f->type == Flit::READ_REPLY || f->type == Flit::WRITE_REPLY ){ + _requestsOutstanding[dest]--; + } else if(f->type == Flit::ANY_TYPE) { + _requestsOutstanding[f->src]--; + } + + } +#endif + + if(f->type == Flit::READ_REPLY || f->type == Flit::WRITE_REPLY ){ + _requestsOutstanding[dest]--; + } else if(f->type == Flit::ANY_TYPE) { + ostringstream err; + err << "Flit " << f->id << " cannot be ANY_TYPE" ; + Error( err.str( ) ); + } + + // Only record statistics once per packet (at tail) + // and based on the simulation state + if ( ( _sim_state == warming_up ) || f->record ) { + + _hop_stats[f->cl]->AddSample( f->hops ); + + if((_slowest_packet[f->cl] < 0) || + (_plat_stats[f->cl]->Max() < (f->atime - head->itime))) + _slowest_packet[f->cl] = f->pid; + _plat_stats[f->cl]->AddSample( f->atime - head->ctime); + _nlat_stats[f->cl]->AddSample( f->atime - head->itime); + _frag_stats[f->cl]->AddSample( (f->atime - head->atime) - (f->id - head->id) ); + + if(_pair_stats){ + _pair_plat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->ctime ); + _pair_nlat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->itime ); + } + } + + if(f != head) { + head->Free(); + } + + } + + if(f->head && !f->tail) { + _retired_packets[f->cl].insert(make_pair(f->pid, f)); + } else { + f->Free(); + } +} +int GPUTrafficManager::_IssuePacket( int source, int cl ) +{ + return 0; +} + +//TODO: Remove stype? +void GPUTrafficManager::_GeneratePacket(int source, int stype, int cl, int time, int subnet, int packet_size, const Flit::FlitType& packet_type, void* const data, int dest) +{ + assert(stype!=0); + + // Flit::FlitType packet_type = Flit::ANY_TYPE; + int size = packet_size; //input size + int pid = _cur_pid++; + assert(_cur_pid); + int packet_destination = dest; + bool record = false; + bool watch = gWatchOut && (_packets_to_watch.count(pid) > 0); + + // In GPGPUSim, the core specified the packet_type and size + +#if 0 + if(_use_read_write[cl]){ + if(stype > 0) { + if (stype == 1) { + packet_type = Flit::READ_REQUEST; + size = _read_request_size[cl]; + } else if (stype == 2) { + packet_type = Flit::WRITE_REQUEST; + size = _write_request_size[cl]; + } else { + ostringstream err; + err << "Invalid packet type: " << packet_type; + Error( err.str( ) ); + } + } else { + PacketReplyInfo* rinfo = _repliesPending[source].front(); + if (rinfo->type == Flit::READ_REQUEST) {//read reply + size = _read_reply_size[cl]; + packet_type = Flit::READ_REPLY; + } else if(rinfo->type == Flit::WRITE_REQUEST) { //write reply + size = _write_reply_size[cl]; + packet_type = Flit::WRITE_REPLY; + } else { + ostringstream err; + err << "Invalid packet type: " << rinfo->type; + Error( err.str( ) ); + } + packet_destination = rinfo->source; + time = rinfo->time; + record = rinfo->record; + _repliesPending[source].pop_front(); + rinfo->Free(); + } + } +#endif + + if ((packet_destination <0) || (packet_destination >= _nodes)) { + ostringstream err; + err << "Incorrect packet destination " << packet_destination + << " for stype " << packet_type; + Error( err.str( ) ); + } + + if ( ( _sim_state == running ) || + ( ( _sim_state == draining ) && ( time < _drain_time ) ) ) { + record = _measure_stats[cl]; + } + + int subnetwork = subnet; + // ((packet_type == Flit::ANY_TYPE) ? + // RandomInt(_subnets-1) : + // _subnet[packet_type]); + + if ( watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << source << " | " + << "Enqueuing packet " << pid + << " at time " << time + << "." << endl; + } + + for ( int i = 0; i < size; ++i ) { + Flit * f = Flit::New(); + f->id = _cur_id++; + assert(_cur_id); + f->pid = pid; + f->watch = watch | (gWatchOut && (_flits_to_watch.count(f->id) > 0)); + f->subnetwork = subnetwork; + f->src = source; + f->ctime = time; + f->record = record; + f->cl = cl; + f->data = data; + + _total_in_flight_flits[f->cl].insert(make_pair(f->id, f)); + if(record) { + _measured_in_flight_flits[f->cl].insert(make_pair(f->id, f)); + } + + if(gTrace){ + cout<<"New Flit "<<f->src<<endl; + } + f->type = packet_type; + + if ( i == 0 ) { // Head flit + f->head = true; + //packets are only generated to nodes smaller or equal to limit + f->dest = packet_destination; + } else { + f->head = false; + f->dest = -1; + } + switch( _pri_type ) { + case class_based: + f->pri = _class_priority[cl]; + assert(f->pri >= 0); + break; + case age_based: + f->pri = numeric_limits<int>::max() - time; + assert(f->pri >= 0); + break; + case sequence_based: + f->pri = numeric_limits<int>::max() - _packet_seq_no[source]; + assert(f->pri >= 0); + break; + default: + f->pri = 0; + } + if ( i == ( size - 1 ) ) { // Tail flit + f->tail = true; + } else { + f->tail = false; + } + + f->vc = -1; + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << source << " | " + << "Enqueuing flit " << f->id + << " (packet " << f->pid + << ") at time " << time + << "." << endl; + } + + _input_queue[subnet][source][cl].push_back( f ); + } +} + +void GPUTrafficManager::_Step() +{ + bool flits_in_flight = false; + for(int c = 0; c < _classes; ++c) { + flits_in_flight |= !_total_in_flight_flits[c].empty(); + } + if(flits_in_flight && (_deadlock_timer++ >= _deadlock_warn_timeout)){ + _deadlock_timer = 0; + cout << "WARNING: Possible network deadlock.\n"; + } + + vector<map<int, Flit *> > flits(_subnets); + + for ( int subnet = 0; subnet < _subnets; ++subnet ) { + for ( int n = 0; n < _nodes; ++n ) { + Flit * const f = _net[subnet]->ReadFlit( n ); + if ( f ) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Ejecting flit " << f->id + << " (packet " << f->pid << ")" + << " from VC " << f->vc + << "." << endl; + } + g_icnt_interface->WriteOutBuffer(subnet, n, f); + } + + g_icnt_interface->Transfer2BoundaryBuffer(subnet, n); + Flit* const ejected_flit = g_icnt_interface->GetEjectedFlit(subnet, n); + if (ejected_flit) { + if(ejected_flit->head) + assert(ejected_flit->dest == n); + if(ejected_flit->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Ejected flit " << ejected_flit->id + << " (packet " << ejected_flit->pid + << " VC " << ejected_flit->vc << ")" + << "from ejection buffer." << endl; + } + flits[subnet].insert(make_pair(n, ejected_flit)); + if((_sim_state == warming_up) || (_sim_state == running)) { + ++_accepted_flits[ejected_flit->cl][n]; + if(ejected_flit->tail) { + ++_accepted_packets[ejected_flit->cl][n]; + } + } + } + + // Processing the credit From the network + Credit * const c = _net[subnet]->ReadCredit( n ); + if ( c ) { +#ifdef TRACK_FLOWS + for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) { + int const vc = *iter; + assert(!_outstanding_classes[n][subnet][vc].empty()); + int cl = _outstanding_classes[n][subnet][vc].front(); + _outstanding_classes[n][subnet][vc].pop(); + assert(_outstanding_credits[cl][subnet][n] > 0); + --_outstanding_credits[cl][subnet][n]; + } +#endif + _buf_states[n][subnet]->ProcessCredit(c); + c->Free(); + } + } + _net[subnet]->ReadInputs( ); + } + +// GPGPUSim will generate/inject packets from interconnection interface +#if 0 + if ( !_empty_network ) { + _Inject(); + } +#endif + + for(int subnet = 0; subnet < _subnets; ++subnet) { + + for(int n = 0; n < _nodes; ++n) { + + Flit * f = NULL; + + BufferState * const dest_buf = _buf_states[n][subnet]; + + int const last_class = _last_class[n][subnet]; + + int class_limit = _classes; + + if(_hold_switch_for_packet) { + list<Flit *> const & pp = _input_queue[subnet][n][last_class]; + if(!pp.empty() && !pp.front()->head && + !dest_buf->IsFullFor(pp.front()->vc)) { + f = pp.front(); + assert(f->vc == _last_vc[n][subnet][last_class]); + + // if we're holding the connection, we don't need to check that class + // again in the for loop + --class_limit; + } + } + + for(int i = 1; i <= class_limit; ++i) { + + int const c = (last_class + i) % _classes; + + list<Flit *> const & pp = _input_queue[subnet][n][c]; + + if(pp.empty()) { + continue; + } + + Flit * const cf = pp.front(); + assert(cf); + assert(cf->cl == c); + + assert(cf->subnetwork == subnet); + + if(f && (f->pri >= cf->pri)) { + continue; + } + + if(cf->head && cf->vc == -1) { // Find first available VC + + OutputSet route_set; + _rf(NULL, cf, -1, &route_set, true); + set<OutputSet::sSetElement> const & os = route_set.GetSet(); + assert(os.size() == 1); + OutputSet::sSetElement const & se = *os.begin(); + assert(se.output_port == -1); + int vc_start = se.vc_start; + int vc_end = se.vc_end; + int vc_count = vc_end - vc_start + 1; + if(_noq) { + assert(_lookahead_routing); + const FlitChannel * inject = _net[subnet]->GetInject(n); + const Router * router = inject->GetSink(); + assert(router); + int in_channel = inject->GetSinkPort(); + + // NOTE: Because the lookahead is not for injection, but for the + // first hop, we have to temporarily set cf's VC to be non-negative + // in order to avoid seting of an assertion in the routing function. + cf->vc = vc_start; + _rf(router, cf, in_channel, &cf->la_route_set, false); + cf->vc = -1; + + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Generating lookahead routing info for flit " << cf->id + << " (NOQ)." << endl; + } + set<OutputSet::sSetElement> const sl = cf->la_route_set.GetSet(); + assert(sl.size() == 1); + int next_output = sl.begin()->output_port; + vc_count /= router->NumOutputs(); + vc_start += next_output * vc_count; + vc_end = vc_start + vc_count - 1; + assert(vc_start >= se.vc_start && vc_start <= se.vc_end); + assert(vc_end >= se.vc_start && vc_end <= se.vc_end); + assert(vc_start <= vc_end); + } + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Finding output VC for flit " << cf->id + << ":" << endl; + } + for(int i = 1; i <= vc_count; ++i) { + int const lvc = _last_vc[n][subnet][c]; + int const vc = + (lvc < vc_start || lvc > vc_end) ? + vc_start : + (vc_start + (lvc - vc_start + i) % vc_count); + assert((vc >= vc_start) && (vc <= vc_end)); + if(!dest_buf->IsAvailableFor(vc)) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Output VC " << vc << " is busy." << endl; + } + } else { + if(dest_buf->IsFullFor(vc)) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Output VC " << vc << " is full." << endl; + } + } else { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Selected output VC " << vc << "." << endl; + } + cf->vc = vc; + break; + } + } + } + } + + if(cf->vc == -1) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "No output VC found for flit " << cf->id + << "." << endl; + } + } else { + if(dest_buf->IsFullFor(cf->vc)) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Selected output VC " << cf->vc + << " is full for flit " << cf->id + << "." << endl; + } + } else { + f = cf; + } + } + } + + if(f) { + + assert(f->subnetwork == subnet); + + int const c = f->cl; + + if(f->head) { + + if (_lookahead_routing) { + if(!_noq) { + const FlitChannel * inject = _net[subnet]->GetInject(n); + const Router * router = inject->GetSink(); + assert(router); + int in_channel = inject->GetSinkPort(); + _rf(router, f, in_channel, &f->la_route_set, false); + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Generating lookahead routing info for flit " << f->id + << "." << endl; + } + } else if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Already generated lookahead routing info for flit " << f->id + << " (NOQ)." << endl; + } + } else { + f->la_route_set.Clear(); + } + + dest_buf->TakeBuffer(f->vc); + _last_vc[n][subnet][c] = f->vc; + } + + _last_class[n][subnet] = c; + + _input_queue[subnet][n][c].pop_front(); + +#ifdef TRACK_FLOWS + ++_outstanding_credits[c][subnet][n]; + _outstanding_classes[n][subnet][f->vc].push(c); +#endif + + dest_buf->SendingFlit(f); + + if(_pri_type == network_age_based) { + f->pri = numeric_limits<int>::max() - _time; + assert(f->pri >= 0); + } + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Injecting flit " << f->id + << " into subnet " << subnet + << " at time " << _time + << " with priority " << f->pri + << "." << endl; + } + f->itime = _time; + + // Pass VC "back" + if(!_input_queue[subnet][n][c].empty() && !f->tail) { + Flit * const nf = _input_queue[subnet][n][c].front(); + nf->vc = f->vc; + } + + if((_sim_state == warming_up) || (_sim_state == running)) { + ++_sent_flits[c][n]; + if(f->head) { + ++_sent_packets[c][n]; + } + } + +#ifdef TRACK_FLOWS + ++_injected_flits[c][n]; +#endif + + _net[subnet]->WriteFlit(f, n); + + } + } + } + //Send the credit To the network + for(int subnet = 0; subnet < _subnets; ++subnet) { + for(int n = 0; n < _nodes; ++n) { + map<int, Flit *>::const_iterator iter = flits[subnet].find(n); + if(iter != flits[subnet].end()) { + Flit * const f = iter->second; + + f->atime = _time; + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Injecting credit for VC " << f->vc + << " into subnet " << subnet + << "." << endl; + } + Credit * const c = Credit::New(); + c->vc.insert(f->vc); + _net[subnet]->WriteCredit(c, n); + +#ifdef TRACK_FLOWS + ++_ejected_flits[f->cl][n]; +#endif + + _RetireFlit(f, n); + } + } + flits[subnet].clear(); + // _InteralStep here + _net[subnet]->Evaluate( ); + _net[subnet]->WriteOutputs( ); + } + + ++_time; + assert(_time); + if(gTrace){ + cout<<"TIME "<<_time<<endl; + } + +} + diff --git a/src/intersim2/gputrafficmanager.hpp b/src/intersim2/gputrafficmanager.hpp new file mode 100644 index 0000000..65d2717 --- /dev/null +++ b/src/intersim2/gputrafficmanager.hpp @@ -0,0 +1,74 @@ +// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda +// The University of British Columbia +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of The University of British Columbia 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 THE COPYRIGHT HOLDER 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. + +#ifndef _GPUTRAFFICMANAGER_HPP_ +#define _GPUTRAFFICMANAGER_HPP_ + +#include <iostream> +#include <vector> +#include <list> + +#include "config_utils.hpp" +#include "stats.hpp" +#include "trafficmanager.hpp" +#include "booksim.hpp" +#include "booksim_config.hpp" +#include "flit.hpp" + +class GPUTrafficManager : public TrafficManager { + +protected: + virtual void _RetireFlit( Flit *f, int dest ); + virtual void _GeneratePacket(int source, int stype, int cl, int time, int subnet, int package_size, const Flit::FlitType& packet_type, void* const data, int dest); + virtual int _IssuePacket( int source, int cl ); + virtual void _Step(); + + // record size of _partial_packets for each subnet + vector<vector<vector<list<Flit *> > > > _input_queue; + +public: + + GPUTrafficManager( const Configuration &config, const vector<Network *> & net ); + virtual ~GPUTrafficManager( ); + + // correspond to TrafficManger::Run/SingleSim + void Init(); + + // TODO: if it is not good... + friend class InterconnectInterface; + + + + // virtual void WriteStats( ostream & os = cout ) const; + // virtual void DisplayStats( ostream & os = cout ) const; + // virtual void DisplayOverallStats( ostream & os = cout ) const; + +}; + + + +#endif diff --git a/src/intersim2/injection.cpp b/src/intersim2/injection.cpp new file mode 100644 index 0000000..b192ce3 --- /dev/null +++ b/src/intersim2/injection.cpp @@ -0,0 +1,190 @@ +// $Id: injection.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include <iostream> +#include <vector> +#include <cassert> +#include <limits> +#include "random_utils.hpp" +#include "injection.hpp" + +using namespace std; + +InjectionProcess::InjectionProcess(int nodes, double rate) + : _nodes(nodes), _rate(rate) +{ + if(nodes <= 0) { + cout << "Error: Number of nodes must be greater than zero." << endl; + exit(-1); + } + if((rate < 0.0) || (rate > 1.0)) { + cout << "Error: Injection process must have load between 0.0 and 1.0." + << endl; + exit(-1); + } +} + +void InjectionProcess::reset() +{ + +} + +InjectionProcess * InjectionProcess::New(string const & inject, int nodes, + double load, + Configuration const * const config) +{ + string process_name; + string param_str; + size_t left = inject.find_first_of('('); + if(left == string::npos) { + process_name = inject; + } else { + process_name = inject.substr(0, left); + size_t right = inject.find_last_of(')'); + if(right == string::npos) { + param_str = inject.substr(left+1); + } else { + param_str = inject.substr(left+1, right-left-1); + } + } + vector<string> params = tokenize_str(param_str); + + InjectionProcess * result = NULL; + if(process_name == "bernoulli") { + result = new BernoulliInjectionProcess(nodes, load); + } else if(process_name == "on_off") { + bool missing_params = false; + double alpha = numeric_limits<double>::quiet_NaN(); + if(params.size() < 1) { + if(config) { + alpha = config->GetFloat("burst_alpha"); + } else { + missing_params = true; + } + } else { + alpha = atof(params[0].c_str()); + } + double beta = numeric_limits<double>::quiet_NaN(); + if(params.size() < 2) { + if(config) { + beta = config->GetFloat("burst_beta"); + } else { + missing_params = true; + } + } else { + beta = atof(params[1].c_str()); + } + double r1 = numeric_limits<double>::quiet_NaN(); + if(params.size() < 3) { + r1 = config ? config->GetFloat("burst_r1") : -1.0; + } else { + r1 = atof(params[2].c_str()); + } + if(missing_params) { + cout << "Missing parameters for injection process: " << inject << endl; + exit(-1); + } + if((alpha < 0.0 && beta < 0.0) || + (alpha < 0.0 && r1 < 0.0) || + (beta < 0.0 && r1 < 0.0) || + (alpha >= 0.0 && beta >= 0.0 && r1 >= 0.0)) { + cout << "Invalid parameters for injection process: " << inject << endl; + exit(-1); + } + vector<int> initial(nodes); + if(params.size() > 3) { + initial = tokenize_int(params[2]); + initial.resize(nodes, initial.back()); + } else { + for(int n = 0; n < nodes; ++n) { + initial[n] = RandomInt(1); + } + } + result = new OnOffInjectionProcess(nodes, load, alpha, beta, r1, initial); + } else { + cout << "Invalid injection process: " << inject << endl; + exit(-1); + } + return result; +} + +//============================================================= + +BernoulliInjectionProcess::BernoulliInjectionProcess(int nodes, double rate) + : InjectionProcess(nodes, rate) +{ + +} + +bool BernoulliInjectionProcess::test(int source) +{ + assert((source >= 0) && (source < _nodes)); + return (RandomFloat() < _rate); +} + +//============================================================= + +OnOffInjectionProcess::OnOffInjectionProcess(int nodes, double rate, + double alpha, double beta, + double r1, vector<int> initial) + : InjectionProcess(nodes, rate), + _alpha(alpha), _beta(beta), _r1(r1), _initial(initial) +{ + assert(alpha <= 1.0); + assert(beta <= 1.0); + assert(r1 <= 1.0); + if(alpha < 0.0) { + assert(beta >= 0.0); + assert(r1 >= 0.0); + _alpha = beta * rate / (r1 - rate); + } else if(beta < 0.0) { + assert(alpha >= 0.0); + assert(r1 >= 0.0); + _beta = alpha * (r1 - rate) / rate; + } else { + assert(r1 < 0.0); + _r1 = rate * (alpha + beta) / alpha; + } + reset(); +} + +void OnOffInjectionProcess::reset() +{ + _state = _initial; +} + +bool OnOffInjectionProcess::test(int source) +{ + assert((source >= 0) && (source < _nodes)); + + // advance state + _state[source] = + _state[source] ? (RandomFloat() >= _beta) : (RandomFloat() < _alpha); + + // generate packet + return _state[source] && (RandomFloat() < _r1); +} diff --git a/src/intersim2/injection.hpp b/src/intersim2/injection.hpp new file mode 100644 index 0000000..53dab67 --- /dev/null +++ b/src/intersim2/injection.hpp @@ -0,0 +1,68 @@ +// $Id: injection.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _INJECTION_HPP_ +#define _INJECTION_HPP_ + +#include "config_utils.hpp" + +using namespace std; + +class InjectionProcess { +protected: + int _nodes; + double _rate; + InjectionProcess(int nodes, double rate); +public: + virtual ~InjectionProcess() {} + virtual bool test(int source) = 0; + virtual void reset(); + static InjectionProcess * New(string const & inject, int nodes, double load, + Configuration const * const config = NULL); +}; + +class BernoulliInjectionProcess : public InjectionProcess { +public: + BernoulliInjectionProcess(int nodes, double rate); + virtual bool test(int source); +}; + +class OnOffInjectionProcess : public InjectionProcess { +private: + double _alpha; + double _beta; + double _r1; + vector<int> _initial; + vector<int> _state; +public: + OnOffInjectionProcess(int nodes, double rate, double alpha, double beta, + double r1, vector<int> initial); + virtual void reset(); + virtual bool test(int source); +}; + +#endif diff --git a/src/intersim2/interconnect_interface.cpp b/src/intersim2/interconnect_interface.cpp new file mode 100644 index 0000000..338e82e --- /dev/null +++ b/src/intersim2/interconnect_interface.cpp @@ -0,0 +1,501 @@ +// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda +// The University of British Columbia +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of The University of British Columbia 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 THE COPYRIGHT HOLDER 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. + +#include <fstream> +#include <iostream> +#include <sstream> +#include <iomanip> +#include <cmath> + +#include "interconnect_interface.hpp" +#include "routefunc.hpp" +#include "globals.hpp" +#include "trafficmanager.hpp" +#include "power_module.hpp" +#include "mem_fetch.h" +#include "flit.hpp" +#include "gputrafficmanager.hpp" +#include "booksim.hpp" +#include "intersim_config.hpp" +#include "network.hpp" + +InterconnectInterface::InterconnectInterface(const char* const config_file, unsigned int n_shader, unsigned int n_mem) +:_n_shader(n_shader), _n_mem(n_mem) +{ + if (! config_file ) { + cout << "Interconnect Requires a configfile" << endl; + exit (-1); + } + _icnt_config = new IntersimConfig(); + _icnt_config->ParseFile(config_file); + + InitializeRoutingMap(*_icnt_config); + + gPrintActivity = (_icnt_config->GetInt("print_activity") > 0); + gTrace = (_icnt_config->GetInt("viewer_trace") > 0); + + string watch_out_file = _icnt_config->GetStr( "watch_out" ); + if(watch_out_file == "") { + gWatchOut = NULL; + } else if(watch_out_file == "-") { + gWatchOut = &cout; + } else { + gWatchOut = new ofstream(watch_out_file.c_str()); + } + + _subnets = _icnt_config->GetInt("subnets"); + assert(_subnets); + + /*To include a new network, must register the network here + *add an else if statement with the name of the network + */ + _net.resize(_subnets); + for (int i = 0; i < _subnets; ++i) { + ostringstream name; + name << "network_" << i; + _net[i] = Network::New( *_icnt_config, name.str() ); + } + + assert(_icnt_config->GetStr("sim_type") == "gpgpusim"); + _traffic_manager = static_cast<GPUTrafficManager*>(TrafficManager::New( *_icnt_config, _net )) ; + + _flit_size = _icnt_config->GetInt( "flit_size" ); + + // Config for interface buffers + if (_icnt_config->GetInt("ejection_buffer_size")) { + _ejection_buffer_capacity = _icnt_config->GetInt( "ejection_buffer_size" ) ; + } else { + _ejection_buffer_capacity = _icnt_config->GetInt( "vc_buf_size" ); + } + + _boundary_buffer_capacity = _icnt_config->GetInt( "boundary_buffer_size" ) ; + assert(_boundary_buffer_capacity); + if (_icnt_config->GetInt("input_buffer_size")) { + _input_buffer_capacity = _icnt_config->GetInt("input_buffer_size"); + } else { + _input_buffer_capacity = 9; + } + _vcs = _icnt_config->GetInt("num_vcs"); + + _CreateBuffer(); + _CreateNodeMap(_n_shader, _n_mem, _traffic_manager->_nodes, _icnt_config->GetInt("use_map")); + +} + +InterconnectInterface::~InterconnectInterface() +{ + for (int i=0; i<_subnets; ++i) { + ///Power analysis + if(_icnt_config->GetInt("sim_power") > 0){ + Power_Module pnet(_net[i], *_icnt_config); + pnet.run(); + } + delete _net[i]; + } + + delete _traffic_manager; + _traffic_manager = NULL; + delete _icnt_config; +} + +void InterconnectInterface::Init() +{ + _traffic_manager->Init(); + // TODO: Should we init _round_robin_turn? + // _boundary_buffer, _ejection_buffer and _ejected_flit_queue should be cleared +} + +void InterconnectInterface::Push(unsigned input_deviceID, unsigned output_deviceID, void *data, unsigned int size) +{ + int output_icntID = _node_map[output_deviceID]; + int input_icntID = _node_map[input_deviceID]; + +#if 0 + cout<<"Call interconnect push input: "<<input<<" output: "<<output<<endl; +#endif + + //TODO: move to _IssuePacket + //TODO: create a Inject and wrap _IssuePacket and _GeneratePacket + unsigned int n_flits = size / _flit_size + ((size % _flit_size)? 1:0); + int subnet; + if (_subnets == 1) { + subnet = 0; + } else { + if (int(input_deviceID) < _n_shader ) { + subnet = 0; + } else { + subnet = 1; + } + } + + Flit::FlitType packet_type; + mem_fetch* mf = static_cast<mem_fetch*>(data); + + switch (mf->get_type()) { + case READ_REQUEST: packet_type = Flit::READ_REQUEST ;break; + case WRITE_REQUEST: packet_type = Flit::WRITE_REQUEST ;break; + case READ_REPLY: packet_type = Flit::READ_REPLY ;break; + case WRITE_ACK: packet_type = Flit::WRITE_REPLY ;break; + default: assert (0); + } + + //TODO: _include_queuing ? + _traffic_manager->_GeneratePacket( input_icntID, -1, 0 /*class*/, _traffic_manager->_time, subnet, n_flits, packet_type, data, output_icntID); + +#if DOUB + cout <<"Traffic[" << subnet << "] (mapped) sending form "<< input_icntID << " to " << output_icntID << endl; +#endif +// } +} + +void* InterconnectInterface::Pop(unsigned deviceID) +{ + int icntID = _node_map[deviceID]; +#if DEBUG + cout<<"Call interconnect POP " << output<<endl; +#endif + + void* data = NULL; + + // 0-_n_shader-1 indicates reply(network 1), otherwise request(network 0) + int subnet = 0; + if (deviceID < _n_shader) + subnet = 1; + + int turn = _round_robin_turn[subnet][icntID]; + for (int vc=0;(vc<_vcs) && (data==NULL);vc++) { + if (_boundary_buffer[subnet][icntID][turn].HasPacket()) { + data = _boundary_buffer[subnet][icntID][turn].PopPacket(); + } + turn++; + if (turn == _vcs) turn = 0; + } + if (data) { + _round_robin_turn[subnet][icntID] = turn; + } + + return data; + +} + +void InterconnectInterface::Advance() +{ + _traffic_manager->_Step(); +} + +bool InterconnectInterface::Busy() const +{ + bool busy = !_traffic_manager->_measured_in_flight_flits[0].empty(); + if (!busy) { + for (int s = 0; s < _subnets; ++s) { + for (int n = 0; n < _n_shader+_n_mem; ++n) { + //FIXME: if this cannot make sure _partial_packets is empty + assert(_traffic_manager->_input_queue[s][n][0].empty()); + } + } + } + else + return true; + for (int s = 0; s < _subnets; ++s) { + for (int n=0; n < (_n_shader+_n_mem); ++n) { + for (int vc=0; vc<_vcs; ++vc) { + if (_boundary_buffer[s][n][vc].HasPacket() ) { + return true; + } + } + } + } + return false; +} + +bool InterconnectInterface::HasBuffer(unsigned deviceID, unsigned int size) const +{ + bool has_buffer = false; + unsigned int n_flits = size / _flit_size + ((size % _flit_size)? 1:0); + int icntID = _node_map.find(deviceID)->second; + + has_buffer = _traffic_manager->_input_queue[0][icntID][0].size() +n_flits <= _input_buffer_capacity; + + if ((_subnets>1) && int(deviceID) >= _n_shader) // deviceID is memory node + has_buffer = _traffic_manager->_input_queue[1][icntID][0].size() +n_flits <= _input_buffer_capacity; + + return has_buffer; +} + +void InterconnectInterface::DisplayStats() const +{ + _traffic_manager->UpdateStats(); + _traffic_manager->DisplayStats(); +} + +unsigned InterconnectInterface::GetFlitSize() const +{ + return _flit_size; +} + +void InterconnectInterface::DisplayOverallStats() const +{ + // hack: booksim2 use _drain_time and calculate delta time based on it, but we don't, change this if you have a better idea + _traffic_manager->_drain_time = _traffic_manager->_time; + // hack: also _total_sims equals to number of kernel calls + _traffic_manager->_total_sims += 1; + + _traffic_manager->_UpdateOverallStats(); + _traffic_manager->DisplayOverallStats(); + if(_traffic_manager->_print_csv_results) { + _traffic_manager->DisplayOverallStatsCSV(); + } +} + +void InterconnectInterface::DisplayState(FILE *fp) const +{ + fprintf(fp, "GPGPU-Sim uArch: ICNT:Display State: Under implementation\n"); +// fprintf(fp,"GPGPU-Sim uArch: interconnect busy state\n"); + +// for (unsigned i=0; i<net_c;i++) { +// if (traffic[i]->_measured_in_flight) +// fprintf(fp," Network %u has %u _measured_in_flight\n", i, traffic[i]->_measured_in_flight ); +// } +// +// for (unsigned i=0 ;i<(_n_shader+_n_mem);i++ ) { +// if( !traffic[0]->_partial_packets[i] [0].empty() ) +// fprintf(fp," Network 0 has nonempty _partial_packets[%u][0]\n", i); +// if ( doub_net && !traffic[1]->_partial_packets[i] [0].empty() ) +// fprintf(fp," Network 1 has nonempty _partial_packets[%u][0]\n", i); +// for (unsigned j=0;j<g_num_vcs;j++ ) { +// if( !ejection_buf[i][j].empty() ) +// fprintf(fp," ejection_buf[%u][%u] is non-empty\n", i, j); +// if( clock_boundary_buf[i][j].has_packet() ) +// fprintf(fp," clock_boundary_buf[%u][%u] has packet\n", i, j ); +// } +// } +} + +void InterconnectInterface::Transfer2BoundaryBuffer(int subnet, int output) +{ + Flit* flit; + int vc; + for (vc=0; vc<_vcs;vc++) { + + if ( !_ejection_buffer[subnet][output][vc].empty() && _boundary_buffer[subnet][output][vc].Size() < _boundary_buffer_capacity ) { + flit = _ejection_buffer[subnet][output][vc].front(); + assert(flit); + + _ejection_buffer[subnet][output][vc].pop(); + _boundary_buffer[subnet][output][vc].PushFlitData( flit->data, flit->tail); + + _ejected_flit_queue[subnet][output].push(flit); //indicate this flit is already popped from ejection buffer and ready for credit return + + if ( flit->head ) { + assert (flit->dest == output); + } + } + } +} + +void InterconnectInterface::WriteOutBuffer(int subnet, int output_icntID, Flit* flit ) +{ + int vc = flit->vc; + assert (_ejection_buffer[subnet][output_icntID][vc].size() < _ejection_buffer_capacity); + _ejection_buffer[subnet][output_icntID][vc].push(flit); +} + +int InterconnectInterface::GetIcntTime() const +{ + return _traffic_manager->getTime(); +} + +Stats* InterconnectInterface::GetIcntStats(const string &name) const +{ + return _traffic_manager->getStats(name); +} + +Flit* InterconnectInterface::GetEjectedFlit(int subnet, int node) +{ + Flit* flit = NULL; + if (!_ejected_flit_queue[subnet][node].empty()) { + flit = _ejected_flit_queue[subnet][node].front(); + _ejected_flit_queue[subnet][node].pop(); + } + return flit; +} + +void InterconnectInterface::_CreateBuffer() +{ + int nodes = _n_shader + _n_mem; + + _boundary_buffer.resize(_subnets); + _ejection_buffer.resize(_subnets); + _round_robin_turn.resize(_subnets); + _ejected_flit_queue.resize(_subnets); + + for (int subnet = 0; subnet < _subnets; ++subnet) { + _ejection_buffer[subnet].resize(nodes); + _boundary_buffer[subnet].resize(nodes); + _round_robin_turn[subnet].resize(nodes); + _ejected_flit_queue[subnet].resize(nodes); + + for (int node=0;node<nodes;++node){ + _ejection_buffer[subnet][node].resize(_vcs); + _boundary_buffer[subnet][node].resize(_vcs); + } + } +} + +void InterconnectInterface::_CreateNodeMap(int n_shader, int n_mem, int n_node, int use_map) +{ + if (use_map) { + map<int, vector<int> > preset_memory_map; + + // good for 8 shaders and 8 memory cores + { + int memory_node[] = {1, 3, 4, 6, 9, 11, 12, 14}; + preset_memory_map[16] = vector<int>(memory_node, memory_node+8); + } + + // good for 28 shaders and 8 memory cores + { + int memory_node[] = {3, 7, 10, 12, 23, 25, 28, 32}; + preset_memory_map[36] = vector<int>(memory_node, memory_node+8); + } + + // good for 56 shaders and 8 memory cores + { + int memory_node[] = {3, 15, 17, 29, 36, 47, 49, 61}; + preset_memory_map[64] = vector<int>(memory_node, memory_node+sizeof(memory_node)/sizeof(int)); + } + + // good for 110 shaders and 11 memory cores + { + int memory_node[] = {12, 20, 25, 28, 57, 60, 63, 92, 95,100,108}; + preset_memory_map[121] = vector<int>(memory_node, memory_node+sizeof(memory_node)/sizeof(int)); + } + + const vector<int> &memory_node = preset_memory_map[n_node]; + if (memory_node.empty()) { + cerr<<"ERROR!!! NO MAPPING IMPLEMENTED YET FOR THIS CONFIG"<<endl; + assert(0); + } + + // create node map + int next_node = 0; + int memory_node_index = 0; + for (int i = 0; i < n_shader; ++i) { + while (next_node == memory_node[memory_node_index]) { + next_node += 1; + memory_node_index += 1; + } + _node_map[i] = next_node; + next_node += 1; + } + for (int i = n_shader; i < n_shader+n_mem; ++i) { + _node_map[i] = memory_node[i-n_shader]; + } + } else { //not use preset map + for (int i=0;i<n_node;i++) { + _node_map[i]=i; + } + } + + for (int i = 0; i < n_node ; i++) { + for (int j = 0; j< n_node ; j++) { + if ( _node_map[j] == i ) { + _reverse_node_map[i]=j; + break; + } + } + } + + //FIXME: should compatible with non-squre number + _DisplayMap((int) sqrt(n_node), n_node); + +} + +void InterconnectInterface::_DisplayMap(int dim,int count) +{ + cout << "GPGPU-Sim uArch: interconnect node map (shaderID+MemID to icntID)" << endl; + cout << "GPGPU-Sim uArch: Memory nodes ID start from index: " << _n_shader << endl; + cout << "GPGPU-Sim uArch: "; + for (int i = 0;i < count; i++) { + cout << setw(4) << _node_map[i]; + if ((i+1)%dim == 0 && i != count-1) + cout << endl << "GPGPU-Sim uArch: "; + } + cout << endl; + + cout << "GPGPU-Sim uArch: interconnect node reverse map (icntID to shaderID+MemID)" << endl; + cout << "GPGPU-Sim uArch: Memory nodes start from ID: " << _n_shader << endl; + cout << "GPGPU-Sim uArch: "; + for (int i = 0;i < count; i++) { + cout << setw(4) << _reverse_node_map[i]; + if ((i+1)%dim == 0 && i != count-1) + cout << endl << "GPGPU-Sim uArch: "; + } + cout << endl; +} + +void* InterconnectInterface::_BoundaryBufferItem::PopPacket() +{ + assert (_packet_n); + void * data = NULL; + void * flit_data = _buffer.front(); + while (data == NULL) { + assert(flit_data == _buffer.front()); //all flits must belong to the same packet + if (_tail_flag.front()) { + data = _buffer.front(); + _packet_n--; + } + _buffer.pop(); + _tail_flag.pop(); + } + return data; +} + +void* InterconnectInterface::_BoundaryBufferItem::TopPacket() const +{ + assert (_packet_n); + void* data = NULL; + void* temp_d = _buffer.front(); + while (data==NULL) { + if (_tail_flag.front()) { + data = _buffer.front(); + } + assert(temp_d == _buffer.front()); //all flits must belong to the same packet + } + return data; + +} + +void InterconnectInterface::_BoundaryBufferItem::PushFlitData(void* data,bool is_tail) +{ + _buffer.push(data); + _tail_flag.push(is_tail); + if (is_tail) { + _packet_n++; + } +} + diff --git a/src/intersim2/interconnect_interface.hpp b/src/intersim2/interconnect_interface.hpp new file mode 100644 index 0000000..6ce4418 --- /dev/null +++ b/src/intersim2/interconnect_interface.hpp @@ -0,0 +1,131 @@ +// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda +// The University of British Columbia +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of The University of British Columbia 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 THE COPYRIGHT HOLDER 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. + +#ifndef _INTERCONNECT_INTERFACE_HPP_ +#define _INTERCONNECT_INTERFACE_HPP_ + +#include <vector> +#include <queue> +#include <iostream> +#include <map> +using namespace std; + + +// Do not use #include since it will not compile in icnt_wrapper or change the makefile to make it +class Flit; +class GPUTrafficManager; +class IntersimConfig; +class Network; +class Stats; + +//TODO: fixed_lat_icnt, add class support? support for signle network + +class InterconnectInterface { +public: + InterconnectInterface(const char* const config_file, unsigned int n_shader, unsigned int n_mem); + virtual ~InterconnectInterface(); + + //node side functions + void Init(); + void Push(unsigned input_deviceID, unsigned output_deviceID, void* data, unsigned int size); + void* Pop(unsigned ouput_deviceID); + void Advance(); + bool Busy() const; + bool HasBuffer(unsigned deviceID, unsigned int size) const; + void DisplayStats() const; + void DisplayOverallStats() const; + unsigned GetFlitSize() const; + + void DisplayState(FILE* fp) const; + + //booksim side functions + void WriteOutBuffer( int subnet, int output, Flit* flit ); + void Transfer2BoundaryBuffer(int subnet, int output); + + int GetIcntTime() const; + + Stats* GetIcntStats(const string & name) const; + + Flit* GetEjectedFlit(int subnet, int node); + + +private: + + class _BoundaryBufferItem { + public: + _BoundaryBufferItem():_packet_n(0) {} + inline unsigned Size(void) const { return _buffer.size(); } + inline bool HasPacket() const { return _packet_n; } + void* PopPacket(); + void* TopPacket() const; + void PushFlitData(void* data,bool is_tail); + + private: + queue<void *> _buffer; + queue<bool> _tail_flag; + int _packet_n; + }; + typedef queue<Flit*> _EjectionBufferItem; + + void _CreateBuffer( ); + void _CreateNodeMap(int n_shader, int n_mem, int n_node, int use_map); + void _DisplayMap(int dim,int count); + + // size: [subnets][nodes][vcs] + vector<vector<vector<_BoundaryBufferItem> > > _boundary_buffer; + unsigned int _boundary_buffer_capacity; + // size: [subnets][nodes][vcs] + vector<vector<vector<_EjectionBufferItem> > > _ejection_buffer; + // size:[subnets][nodes] + vector<vector<queue<Flit* > > > _ejected_flit_queue; + + unsigned int _ejection_buffer_capacity; + unsigned int _input_buffer_capacity; + + vector<vector<int> > _round_robin_turn; //keep track of _boundary_buffer last used in icnt_pop + + GPUTrafficManager* _traffic_manager; + unsigned int _flit_size; + IntersimConfig* _icnt_config; + const int _n_shader, _n_mem; + vector<Network *> _net; + int _vcs; + int _subnets; + + //deviceID to icntID map + //deviceID : Starts from 0 for shaders and then continues until mem nodes + //which starts at location n_shader and then continues to n_shader+n_mem (last device) + map<int, int> _node_map; + + //icntID to deviceID map + map<int, int> _reverse_node_map; + +}; + +#endif + + diff --git a/src/intersim2/intersim_config.cpp b/src/intersim2/intersim_config.cpp new file mode 100644 index 0000000..742fe9a --- /dev/null +++ b/src/intersim2/intersim_config.cpp @@ -0,0 +1,54 @@ +// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda +// The University of British Columbia +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of The University of British Columbia 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 THE COPYRIGHT HOLDER 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. + +#include "intersim_config.hpp" + +IntersimConfig::IntersimConfig() +{ + // Add options for intersim + + _int_map["perfect_icnt"] = 0; // if set overrides fixed_lat_per_hop setting + _int_map["fixed_lat_per_hop"] = 0; // if set icnt is NOT simulated instead packets are sent into destination based on a fixed_lat_per_hop + _int_map["network_count"] = 2; // number of independent interconnection networks (if it is set to 2 then 2 identical networks are created: sh2mem and mem2shd ) + + _int_map["output_extra_latency"] = 0; + + _int_map["use_map"] = 1; + + _int_map["flit_size"] = 32; + //stats + _int_map["enable_link_stats"] = 0; // show output link and VC utilization stats + + _int_map["MATLAB_OUTPUT"] = 0; // output data in MATLAB friendly format + _int_map["DISPLAY_LAT_DIST"] = 0; // distribution of packet latencies + _int_map["DISPLAY_HOP_DIST"] = 0; // distribution of hop counts + _int_map["DISPLAY_PAIR_LATENCY"] = 0; // avg. latency for each s-d pair + + _int_map["input_buffer_size"] = 0; + _int_map["ejection_buffer_size"] = 0; // if left zero the simulator will use the vc_buf_size instead + _int_map["boundary_buffer_size"] = 16; +}
\ No newline at end of file diff --git a/src/intersim2/intersim_config.hpp b/src/intersim2/intersim_config.hpp new file mode 100644 index 0000000..641dd22 --- /dev/null +++ b/src/intersim2/intersim_config.hpp @@ -0,0 +1,39 @@ +// Copyright (c) 2009-2013, Tor M. Aamodt, Dongdong Li, Ali Bakhoda +// The University of British Columbia +// All rights reserved. +// +// 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 following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this +// list of conditions and the following disclaimer in the documentation and/or +// other materials provided with the distribution. +// Neither the name of The University of British Columbia 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 THE COPYRIGHT HOLDER 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. + +#ifndef _INTERSIM_CONFIG_HPP_ +#define _INTERSIM_CONFIG_HPP_ + +#include "config_utils.hpp" +#include "booksim_config.hpp" + +class IntersimConfig : public BookSimConfig { +public: + IntersimConfig(); +}; + +#endif
\ No newline at end of file diff --git a/src/intersim2/main.cpp b/src/intersim2/main.cpp new file mode 100644 index 0000000..9b43fff --- /dev/null +++ b/src/intersim2/main.cpp @@ -0,0 +1,209 @@ +// $Id: main.cpp 5487 2013-02-27 08:16:18Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. + */ + +/*main.cpp + * + *The starting point of the network simulator + *-Include all network header files + *-initilize the network + *-initialize the traffic manager and set it to run + * + * + */ +#include <sys/time.h> + +#include <string> +#include <cstdlib> +#include <iostream> +#include <fstream> + + + +#include <sstream> +#include "booksim.hpp" +#include "routefunc.hpp" +#include "traffic.hpp" +#include "booksim_config.hpp" +#include "trafficmanager.hpp" +#include "random_utils.hpp" +#include "network.hpp" +#include "injection.hpp" +#include "power_module.hpp" +#include "interconnect_interface.hpp" + +/////////////////////////////////////////////////////////////////////////////// +//Global declarations +////////////////////// + +// Interconnect Interface instance +InterconnectInterface *g_icnt_interface; + +/* the current traffic manager instance */ +TrafficManager * trafficManager = NULL; +#if 0 + +int GetSimTime() { + return trafficManager->getTime(); +} + +class Stats; +Stats * GetStats(const std::string & name) { + Stats* test = trafficManager->getStats(name); + if(test == 0){ + cout<<"warning statistics "<<name<<" not found"<<endl; + } + return test; +} +#else +int GetSimTime() { + return g_icnt_interface->GetIcntTime(); +} + +class Stats; +Stats * GetStats(const std::string & name) { + Stats* test = g_icnt_interface->GetIcntStats(name); + if(test == 0){ + cout<<"warning statistics "<<name<<" not found"<<endl; + } + return test; +} + +#endif + +/* printing activity factor*/ +bool gPrintActivity; + +int gK;//radix +int gN;//dimension +int gC;//concentration + +int gNodes; + +//generate nocviewer trace +bool gTrace; + +ostream * gWatchOut; + + + +///////////////////////////////////////////////////////////////////////////// + +bool Simulate( BookSimConfig const & config ) +{ + vector<Network *> net; + + int subnets = config.GetInt("subnets"); + /*To include a new network, must register the network here + *add an else if statement with the name of the network + */ + net.resize(subnets); + for (int i = 0; i < subnets; ++i) { + ostringstream name; + name << "network_" << i; + net[i] = Network::New( config, name.str() ); + } + + /*tcc and characterize are legacy + *not sure how to use them + */ + + assert(trafficManager == NULL); + trafficManager = TrafficManager::New( config, net ) ; + + /*Start the simulation run + */ + + double total_time; /* Amount of time we've run */ + struct timeval start_time, end_time; /* Time before/after user code */ + total_time = 0.0; + gettimeofday(&start_time, NULL); + + bool result = trafficManager->Run() ; + + + gettimeofday(&end_time, NULL); + total_time = ((double)(end_time.tv_sec) + (double)(end_time.tv_usec)/1000000.0) + - ((double)(start_time.tv_sec) + (double)(start_time.tv_usec)/1000000.0); + + cout<<"Total run time "<<total_time<<endl; + + for (int i=0; i<subnets; ++i) { + + ///Power analysis + if(config.GetInt("sim_power") > 0){ + Power_Module pnet(net[i], config); + pnet.run(); + } + + delete net[i]; + } + + delete trafficManager; + trafficManager = NULL; + + return result; +} + +#ifdef CREATE_LIBRARY + +#else +int main( int argc, char **argv ) +{ + + BookSimConfig config; + + + if ( !ParseArgs( &config, argc, argv ) ) { + cerr << "Usage: " << argv[0] << " configfile... [param=value...]" << endl; + return 0; + } + + + /*initialize routing, traffic, injection functions + */ + InitializeRoutingMap( config ); + + gPrintActivity = (config.GetInt("print_activity") > 0); + gTrace = (config.GetInt("viewer_trace") > 0); + + string watch_out_file = config.GetStr( "watch_out" ); + if(watch_out_file == "") { + gWatchOut = NULL; + } else if(watch_out_file == "-") { + gWatchOut = &cout; + } else { + gWatchOut = new ofstream(watch_out_file.c_str()); + } + + + /*configure and run the simulator + */ + bool result = Simulate( config ); + return result ? -1 : 0; +} +#endif + diff --git a/src/intersim2/misc_utils.cpp b/src/intersim2/misc_utils.cpp new file mode 100644 index 0000000..70ba93e --- /dev/null +++ b/src/intersim2/misc_utils.cpp @@ -0,0 +1,52 @@ +// $Id: misc_utils.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include "misc_utils.hpp" + +int powi( int x, int y ) // compute x to the y +{ + int r = 1; + + for ( int i = 0; i < y; ++i ) { + r *= x; + } + + return r; +} + +int log_two( int x ) +{ + int r = 0; + + x >>= 1; + while( x ) { + r++; x >>= 1; + } + + return r; +} diff --git a/src/intersim2/misc_utils.hpp b/src/intersim2/misc_utils.hpp new file mode 100644 index 0000000..5c478a3 --- /dev/null +++ b/src/intersim2/misc_utils.hpp @@ -0,0 +1,34 @@ +// $Id: misc_utils.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _MISC_UTILS_HPP_ +#define _MISC_UTILS_HPP_ + +int log_two( int x ); +int powi( int x, int y ); + +#endif diff --git a/src/intersim2/module.cpp b/src/intersim2/module.cpp new file mode 100644 index 0000000..c6eb605 --- /dev/null +++ b/src/intersim2/module.cpp @@ -0,0 +1,88 @@ +// $Id: module.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*module.cpp + * + *The basic class that is extended by all other components of the network + *Provides the basic hierarchy structure and basic fuctions + * + */ + +#include <iostream> +#include <cstdlib> + +#include "booksim.hpp" +#include "module.hpp" + +Module::Module( Module *parent, const string& name ) +{ + _name = name; + + if ( parent ) { + parent->_AddChild( this ); + _fullname = parent->_fullname + "/" + name; + } else { + _fullname = name; + } +} + +void Module::_AddChild( Module *child ) +{ + _children.push_back( child ); +} + +void Module::DisplayHierarchy( int level, ostream & os ) const +{ + vector<Module *>::const_iterator mod_iter; + + for ( int l = 0; l < level; l++ ) { + os << " "; + } + + os << _name << endl; + + for ( mod_iter = _children.begin( ); + mod_iter != _children.end( ); mod_iter++ ) { + (*mod_iter)->DisplayHierarchy( level + 1 ); + } +} + +void Module::Error( const string& msg ) const +{ + cout << "Error in " << _fullname << " : " << msg << endl; + exit( -1 ); +} + +void Module::Debug( const string& msg ) const +{ + cout << "Debug (" << _fullname << ") : " << msg << endl; +} + +void Module::Display( ostream & os ) const +{ + os << "Display method not implemented for " << _fullname << endl; +} diff --git a/src/intersim2/module.hpp b/src/intersim2/module.hpp new file mode 100644 index 0000000..e24f723 --- /dev/null +++ b/src/intersim2/module.hpp @@ -0,0 +1,62 @@ +// $Id: module.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _MODULE_HPP_ +#define _MODULE_HPP_ + +#include "booksim.hpp" + +#include <string> +#include <vector> +#include <iostream> + +class Module { +private: + string _name; + string _fullname; + + vector<Module *> _children; + +protected: + void _AddChild( Module *child ); + +public: + Module( Module *parent, const string& name ); + virtual ~Module( ) { } + + inline const string & Name() const { return _name; } + inline const string & FullName() const { return _fullname; } + + void DisplayHierarchy( int level = 0, ostream & os = cout ) const; + + void Error( const string& msg ) const; + void Debug( const string& msg ) const; + + virtual void Display( ostream & os = cout ) const; +}; + +#endif diff --git a/src/intersim2/networks/anynet.cpp b/src/intersim2/networks/anynet.cpp new file mode 100644 index 0000000..4db1dfb --- /dev/null +++ b/src/intersim2/networks/anynet.cpp @@ -0,0 +1,501 @@ +// $Id: anynet.cpp 5354 2012-11-07 23:51:49Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*anynet + * + *Network setup file format + *example 1: + *router 0 router 1 15 router 2 + * + *Router 0 is connect to router 1 with a 15-cycle channel, and router 0 is connected to + * router 2 with a 1-cycle channel, the channels latency are unidirectional, so channel + * from router 1 back to router 0 is only single-cycle because it was not specified + * + *example 2: + *router 0 node 0 node 1 5 node 2 5 + * + *Router 0 is directly connected to node 0-2. Channel latency is 5cycles for 1 and 2. In + * this case the latency specification is bidirectional, the injeciton and ejection lat + * for node 1 and 2 are 5-cycle + * + *other notes: + * + *Router and node numbers must be sequential starting with 0 + *Credit channel latency follows the channel latency, even though it travels in revse + * direction this might not be desired + * + */ + +#include "anynet.hpp" +#include <fstream> +#include <sstream> +#include <limits> +#include <algorithm> +//this is a hack, I can't easily get the routing talbe out of the network +map<int, int>* global_routing_table; + +AnyNet::AnyNet( const Configuration &config, const string & name ) + : Network( config, name ){ + + router_list.resize(2); + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + +AnyNet::~AnyNet(){ + for(int i = 0; i < 2; ++i) { + for(map<int, map<int, pair<int,int> > >::iterator iter = router_list[i].begin(); + iter != router_list[i].end(); + ++iter) { + iter->second.clear(); + } + } +} + +void AnyNet::_ComputeSize( const Configuration &config ){ + file_name = config.GetStr("network_file"); + if(file_name==""){ + cout<<"No network file name provided"<<endl; + exit(-1); + } + //parse the network description file + readFile(); + + _channels =0; + cout<<"========================Network File Parsed=================\n"; + cout<<"******************node listing**********************\n"; + map<int, int >::iterator iter; + for(iter = node_list.begin(); iter!=node_list.end(); iter++){ + cout<<"Node "<<iter->first; + cout<<"\tRouter "<<iter->second<<endl; + } + + map<int, map<int, pair<int,int> > >::iterator iter3; + cout<<"\n****************router to node listing*************\n"; + for(iter3 = router_list[0].begin(); iter3!=router_list[0].end(); iter3++){ + cout<<"Router "<<iter3->first<<endl; + map<int, pair<int,int> >::iterator iter2; + for(iter2 = iter3->second.begin(); + iter2!=iter3->second.end(); + iter2++){ + cout<<"\t Node "<<iter2->first<<" lat "<<iter2->second.second<<endl; + } + } + + cout<<"\n*****************router to router listing************\n"; + for(iter3 = router_list[1].begin(); iter3!=router_list[1].end(); iter3++){ + cout<<"Router "<<iter3->first<<endl; + map<int, pair<int,int> >::iterator iter2; + if(iter3->second.size() == 0){ + cout<<"Caution Router "<<iter3->first + <<" is not connected to any other Router\n"<<endl; + } + for(iter2 = iter3->second.begin(); + iter2!=iter3->second.end(); + iter2++){ + cout<<"\t Router "<<iter2->first<<" lat "<<iter2->second.second<<endl; + _channels++; + } + } + + _size = router_list[1].size(); + _nodes = node_list.size(); + +} + + + +void AnyNet::_BuildNet( const Configuration &config ){ + + + //I need to keep track the output ports for each router during build + int * outport = (int*)malloc(sizeof(int)*_size); + for(int i = 0; i<_size; i++){outport[i] = 0;} + + cout<<"==========================Node to Router =====================\n"; + //adding the injection/ejection chanenls first + map<int, map<int, pair<int,int> > >::iterator niter; + for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){ + map<int, map<int, pair<int,int> > >::iterator riter = router_list[1].find(niter->first); + //calculate radix + int radix = niter->second.size()+riter->second.size(); + int node = niter->first; + cout<<"router "<<node<<" radix "<<radix<<endl; + //decalre the routers + ostringstream router_name; + router_name << "router"; + router_name << "_" << node ; + _routers[node] = Router::NewRouter( config, this, router_name.str( ), + node, radix, radix ); + _timed_modules.push_back(_routers[node]); + //add injeciton ejection channels + map<int, pair<int,int> >::iterator nniter; + for(nniter = niter->second.begin();nniter!=niter->second.end(); nniter++){ + int link = nniter->first; + //add the outport port assined to the map + (niter->second)[link].first = outport[node]; + outport[node]++; + cout<<"\t connected to node "<<link<<" at outport "<<nniter->second.first + <<" lat "<<nniter->second.second<<endl; + _inject[link]->SetLatency(nniter->second.second); + _inject_cred[link]->SetLatency(nniter->second.second); + _eject[link]->SetLatency(nniter->second.second); + _eject_cred[link]->SetLatency(nniter->second.second); + + _routers[node]->AddInputChannel( _inject[link], _inject_cred[link] ); + _routers[node]->AddOutputChannel( _eject[link], _eject_cred[link] ); + } + + } + + cout<<"==========================Router to Router =====================\n"; + //add inter router channels + //since there is no way to systematically number the channels we just start from 0 + //the map, is a mapping of output->input + int channel_count = 0; + for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){ + map<int, map<int, pair<int,int> > >::iterator riter = router_list[1].find(niter->first); + int node = niter->first; + map<int, pair<int,int> >::iterator rriter; + cout<<"router "<<node<<endl; + for(rriter = riter->second.begin();rriter!=riter->second.end(); rriter++){ + int other_node = rriter->first; + int link = channel_count; + //add the outport port assined to the map + (riter->second)[other_node].first = outport[node]; + outport[node]++; + cout<<"\t connected to router "<<other_node<<" using link "<<link + <<" at outport "<<rriter->second.first + <<" lat "<<rriter->second.second<<endl; + + _chan[link]->SetLatency(rriter->second.second); + _chan_cred[link]->SetLatency(rriter->second.second); + + _routers[node]->AddOutputChannel( _chan[link], _chan_cred[link] ); + _routers[other_node]->AddInputChannel( _chan[link], _chan_cred[link]); + channel_count++; + } + } + + buildRoutingTable(); + +} + + +void AnyNet::RegisterRoutingFunctions() { + gRoutingFunctionMap["min_anynet"] = &min_anynet; +} + +void min_anynet( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ){ + int out_port=-1; + if(!inject){ + assert(global_routing_table[r->GetID()].count(f->dest)!=0); + out_port=global_routing_table[r->GetID()][f->dest]; + } + + + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + +void AnyNet::buildRoutingTable(){ + cout<<"========================== Routing table =====================\n"; + routing_table.resize(_size); + for(int i = 0; i<_size; i++){ + route(i); + } + global_routing_table = &routing_table[0]; +} + + +//11/7/2012 +//basically djistra's, tested on a large dragonfly anynet configuration +void AnyNet::route(int r_start){ + int* dist = new int[_size]; + int* prev = new int[_size]; + set<int> rlist; + for(int i = 0; i<_size; i++){ + dist[i] = numeric_limits<int>::max(); + prev[i] = -1; + rlist.insert(i); + } + dist[r_start] = 0; + while(!rlist.empty()){ + //find min + int min_dist = numeric_limits<int>::max(); + int min_cand = -1; + for(set<int>::iterator i = rlist.begin(); + i!=rlist.end(); + i++){ + if(dist[*i]<min_dist){ + min_dist = dist[*i]; + min_cand = *i; + } + } + rlist.erase(min_cand); + + //neighbor + for(map<int,pair<int,int> >::iterator i = router_list[1][min_cand].begin(); + i!=router_list[1][min_cand].end(); + i++){ + int new_dist = dist[min_cand] + i->second.second;//distance is hops not cycles + if(new_dist < dist[i->first]){ + dist[i->first] = new_dist; + prev[i->first] = min_cand; + } + } + } + + //post process from the prev list + for(int i = 0; i<_size; i++){ + if(prev[i] ==-1){ //self + assert(i == r_start); + for(map<int, pair<int, int> >::iterator iter = router_list[0][i].begin(); + iter!=router_list[0][i].end(); + iter++){ + routing_table[r_start][iter->first]=iter->second.first; + //cout<<"node "<<iter->first<<" port "<< iter->second.first<<endl; + } + } else { + int distance=0; + int neighbor=i; + while(prev[neighbor]!=r_start){ + assert(router_list[1][neighbor].count(prev[neighbor])>0); + distance+=router_list[1][prev[neighbor]][neighbor].second;//REVERSE lat + neighbor= prev[neighbor]; + } + distance+=router_list[1][prev[neighbor]][neighbor].second;//lat + + assert( router_list[1][r_start].count(neighbor)!=0); + int port = router_list[1][r_start][neighbor].first; + for(map<int, pair<int,int> >::iterator iter = router_list[0][i].begin(); + iter!=router_list[0][i].end(); + iter++){ + routing_table[r_start][iter->first]=port; + //cout<<"node "<<iter->first<<" port "<< port<<" dist "<<distance<<endl; + } + } + } +} + + +void AnyNet::readFile(){ + + ifstream network_list; + string line; + enum ParseState{HEAD_TYPE=0, + HEAD_ID, + BODY_TYPE, + BODY_ID, + LINK_WEIGHT}; + enum ParseType{NODE=0, + ROUTER, + UNKNOWN}; + + network_list.open(file_name.c_str()); + if(!network_list.is_open()){ + cout<<"Anynet:can't open network file "<<file_name<<endl; + exit(-1); + } + + //loop through the entire file + while(!network_list.eof()){ + getline(network_list,line); + if(line==""){ + continue; + } + + ParseState state=HEAD_TYPE; + //position to parse out white sspace + int pos = 0; + int next_pos=-1; + string temp; + //the first node and its type + int head_id = -1; + ParseType head_type = UNKNOWN; + //stuff that head are linked to + ParseType body_type = UNKNOWN; + int body_id = -1; + int link_weight = 1; + + do{ + + //skip empty spaces + next_pos = line.find(" ",pos); + temp = line.substr(pos,next_pos-pos); + pos = next_pos+1; + if(temp=="" || temp==" "){ + continue; + } + + switch(state){ + case HEAD_TYPE: + if(temp=="router"){ + head_type = ROUTER; + } else if (temp == "node"){ + head_type = NODE; + } else { + cout<<"Anynet:Unknow head of line type "<<temp<<"\n"; + assert(false); + } + state=HEAD_ID; + break; + case HEAD_ID: + //need better error check + head_id = atoi(temp.c_str()); + + //intialize router structures + if(router_list[NODE].count(head_id) == 0){ + router_list[NODE][head_id] = map<int, pair<int,int> >(); + } + if(router_list[ROUTER].count(head_id) == 0){ + router_list[ROUTER][head_id] = map<int, pair<int,int> >(); + } + + state=BODY_TYPE; + break; + case LINK_WEIGHT: + if(temp=="router"|| + temp == "node"){ + //ignore + } else { + link_weight= atoi(temp.c_str()); + router_list[head_type][head_id][body_id].second=link_weight; + break; + } + //intentionally letting it flow through + case BODY_TYPE: + if(temp=="router"){ + body_type = ROUTER; + } else if (temp == "node"){ + body_type = NODE; + } else { + cout<<"Anynet:Unknow body type "<<temp<<"\n"; + assert(false); + } + state=BODY_ID; + break; + case BODY_ID: + body_id = atoi(temp.c_str()); + //intialize router structures if necessary + if(body_type==ROUTER){ + if(router_list[NODE].count(body_id) ==0){ + router_list[NODE][body_id] = map<int, pair<int,int> >(); + } + if(router_list[ROUTER].count(body_id) == 0){ + router_list[ROUTER][body_id] = map<int, pair<int,int> >(); + } + } + + if(head_type==NODE && body_type==NODE){ + + cout<<"Anynet:Cannot connect node to node "<<temp<<"\n"; + assert(false); + + } else if(head_type==NODE && body_type==ROUTER){ + + if(node_list.count(head_id)!=0 && + node_list[head_id]!=body_id){ + cout<<"Anynet:Node "<<body_id<<" trying to connect to multiple router " + <<body_id<<" and "<<node_list[head_id]<<endl; + assert(false); + } + node_list[head_id]=body_id; + router_list[NODE][body_id][head_id]=pair<int, int>(-1,1); + + } else if(head_type==ROUTER && body_type==NODE){ + //insert and check node + if(node_list.count(body_id) != 0 && + node_list[body_id]!=head_id){ + cout<<"Anynet:Node "<<body_id<<" trying to connect to multiple router " + <<body_id<<" and "<<node_list[head_id]<<endl; + assert(false); + } + node_list[body_id] = head_id; + router_list[NODE][head_id][body_id]=pair<int, int>(-1,1); + + } else if(head_type==ROUTER && body_type==ROUTER){ + router_list[ROUTER][head_id][body_id]=pair<int, int>(-1,1); + if(router_list[ROUTER][body_id].count(head_id)==0){ + router_list[ROUTER][body_id][head_id]=pair<int, int>(-1,1); + } + } + state=LINK_WEIGHT; + break ; + default: + cout<<"Anynet:Unknow parse state\n"; + assert(false); + break; + } + + } while(pos!=0); + if(state!=LINK_WEIGHT && + state!=BODY_TYPE){ + cout<<"Anynet:Incomplete parse of the line: "<<line<<endl; + } + + } + + //map verification, make sure the information contained in bother maps + //are the same + assert(router_list[0].size() == router_list[1].size()); + + //traffic generator assumes node list is sequenctial and starts at 0 + vector<int> node_check; + for(map<int,int>::iterator i = node_list.begin(); + i!=node_list.end(); + i++){ + node_check.push_back(i->first); + } + sort(node_check.begin(), node_check.end()); + for(size_t i = 0; i<node_check.size(); i++){ + if(node_check[i] != i){ + cout<<"Anynet:booksim trafficmanager assumes sequential node numbering starting at 0\n"; + assert(false); + } + } + +} + diff --git a/src/intersim2/networks/anynet.hpp b/src/intersim2/networks/anynet.hpp new file mode 100644 index 0000000..1cfe904 --- /dev/null +++ b/src/intersim2/networks/anynet.hpp @@ -0,0 +1,69 @@ +// $Id: anynet.hpp 5354 2012-11-07 23:51:49Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _ANYNET_HPP_ +#define _ANYNET_HPP_ + +#include "network.hpp" +#include "routefunc.hpp" +#include <cassert> +#include <string> +#include <map> +#include <list> + +class AnyNet : public Network { + + string file_name; + //associtation between nodes and routers + map<int, int > node_list; + //[link type][src router][dest router]=(port, latency) + vector<map<int, map<int, pair<int,int> > > > router_list; + //stores minimal routing information from every router to every node + //[router][dest_node]=port + vector<map<int, int> > routing_table; + + void _ComputeSize( const Configuration &config ); + void _BuildNet( const Configuration &config ); + void readFile(); + void buildRoutingTable(); + void route(int r_start); + +public: + AnyNet( const Configuration &config, const string & name ); + ~AnyNet(); + + int GetN( ) const{ return -1;} + int GetK( ) const{ return -1;} + + static void RegisterRoutingFunctions(); + double Capacity( ) const {return -1;} + void InsertRandomFaults( const Configuration &config ){} +}; + +void min_anynet( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +#endif diff --git a/src/intersim2/networks/cmesh.cpp b/src/intersim2/networks/cmesh.cpp new file mode 100644 index 0000000..06580d3 --- /dev/null +++ b/src/intersim2/networks/cmesh.cpp @@ -0,0 +1,856 @@ +// $Id: cmesh.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +// ---------------------------------------------------------------------- +// +// CMesh: Network with <Int> Terminal Nodes arranged in a concentrated +// mesh topology +// +// ---------------------------------------------------------------------- + +// ---------------------------------------------------------------------- +// $Author: jbalfour $ +// $Date: 2007/06/28 17:24:35 $ +// $Id: cmesh.cpp 5188 2012-08-30 00:31:31Z dub $ +// Modified 11/6/2007 by Ted Jiang +// Now handeling n = most power of 2: 16, 64, 256, 1024 +// ---------------------------------------------------------------------- +#include "booksim.hpp" +#include <vector> +#include <sstream> +#include <cassert> +#include "random_utils.hpp" +#include "misc_utils.hpp" +#include "cmesh.hpp" + +int CMesh::_cX = 0 ; +int CMesh::_cY = 0 ; +int CMesh::_memo_NodeShiftX = 0 ; +int CMesh::_memo_NodeShiftY = 0 ; +int CMesh::_memo_PortShiftY = 0 ; + +CMesh::CMesh( const Configuration& config, const string & name ) + : Network(config, name) +{ + _ComputeSize( config ); + _Alloc(); + _BuildNet(config); +} + +void CMesh::RegisterRoutingFunctions() { + gRoutingFunctionMap["dor_cmesh"] = &dor_cmesh; + gRoutingFunctionMap["dor_no_express_cmesh"] = &dor_no_express_cmesh; + gRoutingFunctionMap["xy_yx_cmesh"] = &xy_yx_cmesh; + gRoutingFunctionMap["xy_yx_no_express_cmesh"] = &xy_yx_no_express_cmesh; +} + +void CMesh::_ComputeSize( const Configuration &config ) { + + int k = config.GetInt( "k" ); + int n = config.GetInt( "n" ); + assert(n <= 2); // broken for n > 2 + int c = config.GetInt( "c" ); + assert(c == 4); // broken for c != 4 + + ostringstream router_name; + //how many routers in the x or y direction + _xcount = config.GetInt("x"); + _ycount = config.GetInt("y"); + assert(_xcount == _ycount); // broken for asymmetric topologies + //configuration of hohw many clients in X and Y per router + _xrouter = config.GetInt("xr"); + _yrouter = config.GetInt("yr"); + assert(_xrouter == _yrouter); // broken for asymmetric concentration + + gK = _k = k ; + gN = _n = n ; + gC = _c = c ; + + assert(c == _xrouter*_yrouter); + + _nodes = _c * powi( _k, _n); // Number of nodes in network + _size = powi( _k, _n); // Number of routers in network + _channels = 2 * _n * _size; // Number of channels in network + + _cX = _c / _n ; // Concentration in X Dimension + _cY = _c / _cX ; // Concentration in Y Dimension + + // + _memo_NodeShiftX = _cX >> 1 ; + _memo_NodeShiftY = log_two(gK * _cX) + ( _cY >> 1 ) ; + _memo_PortShiftY = log_two(gK * _cX) ; + +} + +void CMesh::_BuildNet( const Configuration& config ) { + + int x_index ; + int y_index ; + + //standard trace configuration + if(gTrace){ + cout<<"Setup Finished Router"<<endl; + } + + //latency type, noc or conventional network + bool use_noc_latency; + use_noc_latency = (config.GetInt("use_noc_latency")==1); + + ostringstream name; + // The following vector is used to check that every + // processor in the system is connected to the network + vector<bool> channel_vector(_nodes, false) ; + + // + // Routers and Channel + // + for (int node = 0; node < _size; ++node) { + + // Router index derived from mesh index + y_index = node / _k ; + x_index = node % _k ; + + const int degree_in = 2 *_n + _c ; + const int degree_out = 2 *_n + _c ; + + name << "router_" << y_index << '_' << x_index; + _routers[node] = Router::NewRouter( config, + this, + name.str(), + node, + degree_in, + degree_out); + _timed_modules.push_back(_routers[node]); + name.str(""); + + // + // Port Numbering: as best as I can determine, the order in + // which the input and output channels are added to the + // router determines the associated port number that must be + // used by the router. Output port number increases with + // each new channel + // + + // + // Processing node channels + // + for (int y = 0; y < _cY ; y++) { + for (int x = 0; x < _cX ; x++) { + int link = (_k * _cX) * (_cY * y_index + y) + (_cX * x_index + x) ; + assert( link >= 0 ) ; + assert( link < _nodes ) ; + assert( channel_vector[ link ] == false ) ; + channel_vector[link] = true ; + // Ingress Ports + _routers[node]->AddInputChannel(_inject[link], _inject_cred[link]); + // Egress Ports + _routers[node]->AddOutputChannel(_eject[link], _eject_cred[link]); + //injeciton ejection latency is 1 + _inject[link]->SetLatency( 1 ); + _eject[link]->SetLatency( 1 ); + } + } + + // + // router to router channels + // + const int x = node % _k ; + const int y = node / _k ; + const int offset = powi( _k, _n ) ; + + //the channel number of the input output channels. + int px_out = _k * y + x + 0 * offset ; + int nx_out = _k * y + x + 1 * offset ; + int py_out = _k * y + x + 2 * offset ; + int ny_out = _k * y + x + 3 * offset ; + int px_in = _k * y + ((x+1)) + 1 * offset ; + int nx_in = _k * y + ((x-1)) + 0 * offset ; + int py_in = _k * ((y+1)) + x + 3 * offset ; + int ny_in = _k * ((y-1)) + x + 2 * offset ; + + // Express Channels + if (x == 0){ + // Router on left edge of mesh. Connect to -x output of + // another router on the left edge of the mesh. + if (y < _k / 2 ) + nx_in = _k * (y + _k/2) + x + offset ; + else + nx_in = _k * (y - _k/2) + x + offset ; + } + + if (x == (_k-1)){ + // Router on right edge of mesh. Connect to +x output of + // another router on the right edge of the mesh. + if (y < _k / 2) + px_in = _k * (y + _k/2) + x ; + else + px_in = _k * (y - _k/2) + x ; + } + + if (y == 0) { + // Router on bottom edge of mesh. Connect to -y output of + // another router on the bottom edge of the mesh. + if (x < _k / 2) + ny_in = _k * y + (x + _k/2) + 3 * offset ; + else + ny_in = _k * y + (x - _k/2) + 3 * offset ; + } + + if (y == (_k-1)) { + // Router on top edge of mesh. Connect to +y output of + // another router on the top edge of the mesh + if (x < _k / 2) + py_in = _k * y + (x + _k/2) + 2 * offset ; + else + py_in = _k * y + (x - _k/2) + 2 * offset ; + } + + /*set latency and add the channels*/ + + // Port 0: +x channel + if(use_noc_latency) { + int const px_latency = (x == _k-1) ? (_cY*_k/2) : _cX; + _chan[px_out]->SetLatency( px_latency ); + _chan_cred[px_out]->SetLatency( px_latency ); + } else { + _chan[px_out]->SetLatency( 1 ); + _chan_cred[px_out]->SetLatency( 1 ); + } + _routers[node]->AddOutputChannel( _chan[px_out], _chan_cred[px_out] ); + _routers[node]->AddInputChannel( _chan[px_in], _chan_cred[px_in] ); + + if(gTrace) { + cout<<"Link "<<" "<<px_out<<" "<<px_in<<" "<<node<<" "<<_chan[px_out]->GetLatency()<<endl; + } + + // Port 1: -x channel + if(use_noc_latency) { + int const nx_latency = (x == 0) ? (_cY*_k/2) : _cX; + _chan[nx_out]->SetLatency( nx_latency ); + _chan_cred[nx_out]->SetLatency( nx_latency ); + } else { + _chan[nx_out]->SetLatency( 1 ); + _chan_cred[nx_out]->SetLatency( 1 ); + } + _routers[node]->AddOutputChannel( _chan[nx_out], _chan_cred[nx_out] ); + _routers[node]->AddInputChannel( _chan[nx_in], _chan_cred[nx_in] ); + + if(gTrace){ + cout<<"Link "<<" "<<nx_out<<" "<<nx_in<<" "<<node<<" "<<_chan[nx_out]->GetLatency()<<endl; + } + + // Port 2: +y channel + if(use_noc_latency) { + int const py_latency = (y == _k-1) ? (_cX*_k/2) : _cY; + _chan[py_out]->SetLatency( py_latency ); + _chan_cred[py_out]->SetLatency( py_latency ); + } else { + _chan[py_out]->SetLatency( 1 ); + _chan_cred[py_out]->SetLatency( 1 ); + } + _routers[node]->AddOutputChannel( _chan[py_out], _chan_cred[py_out] ); + _routers[node]->AddInputChannel( _chan[py_in], _chan_cred[py_in] ); + + if(gTrace){ + cout<<"Link "<<" "<<py_out<<" "<<py_in<<" "<<node<<" "<<_chan[py_out]->GetLatency()<<endl; + } + + // Port 3: -y channel + if(use_noc_latency){ + int const ny_latency = (y == 0) ? (_cX*_k/2) : _cY; + _chan[ny_out]->SetLatency( ny_latency ); + _chan_cred[ny_out]->SetLatency( ny_latency ); + } else { + _chan[ny_out]->SetLatency( 1 ); + _chan_cred[ny_out]->SetLatency( 1 ); + } + _routers[node]->AddOutputChannel( _chan[ny_out], _chan_cred[ny_out] ); + _routers[node]->AddInputChannel( _chan[ny_in], _chan_cred[ny_in] ); + + if(gTrace){ + cout<<"Link "<<" "<<ny_out<<" "<<ny_in<<" "<<node<<" "<<_chan[ny_out]->GetLatency()<<endl; + } + + } + + // Check that all processors were connected to the network + for ( int i = 0 ; i < _nodes ; i++ ) + assert( channel_vector[i] == true ) ; + + if(gTrace){ + cout<<"Setup Finished Link"<<endl; + } +} + + +// ---------------------------------------------------------------------- +// +// Routing Helper Functions +// +// ---------------------------------------------------------------------- + +int CMesh::NodeToRouter( int address ) { + + int y = (address / (_cX*gK))/_cY ; + int x = (address % (_cX*gK))/_cY ; + int router = y*gK + x ; + + return router ; +} + +int CMesh::NodeToPort( int address ) { + + const int maskX = _cX - 1 ; + const int maskY = _cY - 1 ; + + int x = address & maskX ; + int y = (int)(address/(2*gK)) & maskY ; + + return (gC / 2) * y + x; +} + +// ---------------------------------------------------------------------- +// +// Routing Functions +// +// ---------------------------------------------------------------------- + +// Concentrated Mesh: X-Y +int cmesh_xy( int cur, int dest ) { + + const int POSITIVE_X = 0 ; + const int NEGATIVE_X = 1 ; + const int POSITIVE_Y = 2 ; + const int NEGATIVE_Y = 3 ; + + int cur_y = cur / gK; + int cur_x = cur % gK; + int dest_y = dest / gK; + int dest_x = dest % gK; + + // Dimension-order Routing: x , y + if (cur_x < dest_x) { + // Express? + if ((dest_x - cur_x) > 1){ + if (cur_y == 0) + return gC + NEGATIVE_Y ; + if (cur_y == (gK-1)) + return gC + POSITIVE_Y ; + } + return gC + POSITIVE_X ; + } + if (cur_x > dest_x) { + // Express ? + if ((cur_x - dest_x) > 1){ + if (cur_y == 0) + return gC + NEGATIVE_Y ; + if (cur_y == (gK-1)) + return gC + POSITIVE_Y ; + } + return gC + NEGATIVE_X ; + } + if (cur_y < dest_y) { + // Express? + if ((dest_y - cur_y) > 1) { + if (cur_x == 0) + return gC + NEGATIVE_X ; + if (cur_x == (gK-1)) + return gC + POSITIVE_X ; + } + return gC + POSITIVE_Y ; + } + if (cur_y > dest_y) { + // Express ? + if ((cur_y - dest_y) > 1 ){ + if (cur_x == 0) + return gC + NEGATIVE_X ; + if (cur_x == (gK-1)) + return gC + POSITIVE_X ; + } + return gC + NEGATIVE_Y ; + } + return 0; +} + +// Concentrated Mesh: Y-X +int cmesh_yx( int cur, int dest ) { + const int POSITIVE_X = 0 ; + const int NEGATIVE_X = 1 ; + const int POSITIVE_Y = 2 ; + const int NEGATIVE_Y = 3 ; + + int cur_y = cur / gK ; + int cur_x = cur % gK ; + int dest_y = dest / gK ; + int dest_x = dest % gK ; + + // Dimension-order Routing: y, x + if (cur_y < dest_y) { + // Express? + if ((dest_y - cur_y) > 1) { + if (cur_x == 0) + return gC + NEGATIVE_X ; + if (cur_x == (gK-1)) + return gC + POSITIVE_X ; + } + return gC + POSITIVE_Y ; + } + if (cur_y > dest_y) { + // Express ? + if ((cur_y - dest_y) > 1 ){ + if (cur_x == 0) + return gC + NEGATIVE_X ; + if (cur_x == (gK-1)) + return gC + POSITIVE_X ; + } + return gC + NEGATIVE_Y ; + } + if (cur_x < dest_x) { + // Express? + if ((dest_x - cur_x) > 1){ + if (cur_y == 0) + return gC + NEGATIVE_Y ; + if (cur_y == (gK-1)) + return gC + POSITIVE_Y ; + } + return gC + POSITIVE_X ; + } + if (cur_x > dest_x) { + // Express ? + if ((cur_x - dest_x) > 1){ + if (cur_y == 0) + return gC + NEGATIVE_Y ; + if (cur_y == (gK-1)) + return gC + POSITIVE_Y ; + } + return gC + NEGATIVE_X ; + } + return 0; +} + +void xy_yx_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + // Current Router + int cur_router = r->GetID(); + + // Destination Router + int dest_router = CMesh::NodeToRouter( f->dest ) ; + + if (dest_router == cur_router) { + + // Forward to processing element + out_port = CMesh::NodeToPort( f->dest ); + + } else { + + // Forward to neighbouring router + + //each class must have at least 2 vcs assigned or else xy_yx will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + // randomly select dimension order at first hop + bool x_then_y = ((in_channel < gC) ? + (RandomInt(1) > 0) : + (f->vc < (vcBegin + available_vcs))); + + if(x_then_y) { + out_port = cmesh_xy( cur_router, dest_router ); + vcEnd -= available_vcs; + } else { + out_port = cmesh_yx( cur_router, dest_router ); + vcBegin += available_vcs; + } + } + + } + + outputs->Clear(); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + +// ---------------------------------------------------------------------- +// +// Concentrated Mesh: Random XY-YX w/o Express Links +// +// <int> cur: current router address +/// <int> dest: destination router address +// +// ---------------------------------------------------------------------- + +int cmesh_xy_no_express( int cur, int dest ) { + + const int POSITIVE_X = 0 ; + const int NEGATIVE_X = 1 ; + const int POSITIVE_Y = 2 ; + const int NEGATIVE_Y = 3 ; + + const int cur_y = cur / gK ; + const int cur_x = cur % gK ; + const int dest_y = dest / gK ; + const int dest_x = dest % gK ; + + + // Note: channel numbers bellow gC (degree of concentration) are + // injection and ejection links + + // Dimension-order Routing: X , Y + if (cur_x < dest_x) { + return gC + POSITIVE_X ; + } + if (cur_x > dest_x) { + return gC + NEGATIVE_X ; + } + if (cur_y < dest_y) { + return gC + POSITIVE_Y ; + } + if (cur_y > dest_y) { + return gC + NEGATIVE_Y ; + } + return 0; +} + +int cmesh_yx_no_express( int cur, int dest ) { + + const int POSITIVE_X = 0 ; + const int NEGATIVE_X = 1 ; + const int POSITIVE_Y = 2 ; + const int NEGATIVE_Y = 3 ; + + const int cur_y = cur / gK ; + const int cur_x = cur % gK ; + const int dest_y = dest / gK ; + const int dest_x = dest % gK ; + + // Note: channel numbers bellow gC (degree of concentration) are + // injection and ejection links + + // Dimension-order Routing: X , Y + if (cur_y < dest_y) { + return gC + POSITIVE_Y ; + } + if (cur_y > dest_y) { + return gC + NEGATIVE_Y ; + } + if (cur_x < dest_x) { + return gC + POSITIVE_X ; + } + if (cur_x > dest_x) { + return gC + NEGATIVE_X ; + } + return 0; +} + +void xy_yx_no_express_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + // Current Router + int cur_router = r->GetID(); + + // Destination Router + int dest_router = CMesh::NodeToRouter( f->dest ); + + if (dest_router == cur_router) { + + // Forward to processing element + out_port = CMesh::NodeToPort( f->dest ); + + } else { + + // Forward to neighbouring router + + //each class must have at least 2 vcs assigned or else xy_yx will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + // randomly select dimension order at first hop + bool x_then_y = ((in_channel < gC) ? + (RandomInt(1) > 0) : + (f->vc < (vcBegin + available_vcs))); + + if(x_then_y) { + out_port = cmesh_xy_no_express( cur_router, dest_router ); + vcEnd -= available_vcs; + } else { + out_port = cmesh_yx_no_express( cur_router, dest_router ); + vcBegin += available_vcs; + } + } + } + + outputs->Clear(); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} +//============================================================ +// +//===== +int cmesh_next( int cur, int dest ) { + + const int POSITIVE_X = 0 ; + const int NEGATIVE_X = 1 ; + const int POSITIVE_Y = 2 ; + const int NEGATIVE_Y = 3 ; + + int cur_y = cur / gK ; + int cur_x = cur % gK ; + int dest_y = dest / gK ; + int dest_x = dest % gK ; + + // Dimension-order Routing: x , y + if (cur_x < dest_x) { + // Express? + if ((dest_x - cur_x) > gK/2-1){ + if (cur_y == 0) + return gC + NEGATIVE_Y ; + if (cur_y == (gK-1)) + return gC + POSITIVE_Y ; + } + return gC + POSITIVE_X ; + } + if (cur_x > dest_x) { + // Express ? + if ((cur_x - dest_x) > gK/2-1){ + if (cur_y == 0) + return gC + NEGATIVE_Y ; + if (cur_y == (gK-1)) + return gC + POSITIVE_Y ; + } + return gC + NEGATIVE_X ; + } + if (cur_y < dest_y) { + // Express? + if ((dest_y - cur_y) > gK/2-1) { + if (cur_x == 0) + return gC + NEGATIVE_X ; + if (cur_x == (gK-1)) + return gC + POSITIVE_X ; + } + return gC + POSITIVE_Y ; + } + if (cur_y > dest_y) { + // Express ? + if ((cur_y - dest_y) > gK/2-1){ + if (cur_x == 0) + return gC + NEGATIVE_X ; + if (cur_x == (gK-1)) + return gC + POSITIVE_X ; + } + return gC + NEGATIVE_Y ; + } + + assert(false); + return -1; +} + +void dor_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + // Current Router + int cur_router = r->GetID(); + + // Destination Router + int dest_router = CMesh::NodeToRouter( f->dest ) ; + + if (dest_router == cur_router) { + + // Forward to processing element + out_port = CMesh::NodeToPort( f->dest ) ; + + } else { + + // Forward to neighbouring router + out_port = cmesh_next( cur_router, dest_router ); + } + } + + outputs->Clear(); + + outputs->AddRange( out_port, vcBegin, vcEnd); +} + +//============================================================ +// +//===== +int cmesh_next_no_express( int cur, int dest ) { + + const int POSITIVE_X = 0 ; + const int NEGATIVE_X = 1 ; + const int POSITIVE_Y = 2 ; + const int NEGATIVE_Y = 3 ; + + //magic constant 2, which is supose to be _cX and _cY + int cur_y = cur/gK ; + int cur_x = cur%gK ; + int dest_y = dest/gK; + int dest_x = dest%gK ; + + // Dimension-order Routing: x , y + if (cur_x < dest_x) { + return gC + POSITIVE_X ; + } + if (cur_x > dest_x) { + return gC + NEGATIVE_X ; + } + if (cur_y < dest_y) { + return gC + POSITIVE_Y ; + } + if (cur_y > dest_y) { + return gC + NEGATIVE_Y ; + } + assert(false); + return -1; +} + +void dor_no_express_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + // Current Router + int cur_router = r->GetID(); + + // Destination Router + int dest_router = CMesh::NodeToRouter( f->dest ) ; + + if (dest_router == cur_router) { + + // Forward to processing element + out_port = CMesh::NodeToPort( f->dest ); + + } else { + + // Forward to neighbouring router + out_port = cmesh_next_no_express( cur_router, dest_router ); + } + } + + outputs->Clear(); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} diff --git a/src/intersim2/networks/cmesh.hpp b/src/intersim2/networks/cmesh.hpp new file mode 100644 index 0000000..1ee55a6 --- /dev/null +++ b/src/intersim2/networks/cmesh.hpp @@ -0,0 +1,95 @@ +// $Id: cmesh.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// CMesh: Mesh topology with concentration and express links along the +// edge of the network +// +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/06/26 22:49:23 $ +// $Id: cmesh.hpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// +#ifndef _CMESH_HPP_ +#define _CMESH_HPP_ + +#include "network.hpp" +#include "routefunc.hpp" + +class CMesh : public Network { +public: + CMesh( const Configuration &config, const string & name ); + int GetN() const; + int GetK() const; + + static int NodeToRouter( int address ) ; + static int NodeToPort( int address ) ; + + static void RegisterRoutingFunctions() ; + +private: + + static int _cX ; + static int _cY ; + + static int _memo_NodeShiftX ; + static int _memo_NodeShiftY ; + static int _memo_PortShiftY ; + + void _ComputeSize( const Configuration &config ); + void _BuildNet( const Configuration& config ); + + int _k ; + int _n ; + int _c ; + int _xcount; + int _ycount; + int _xrouter; + int _yrouter; + bool _express_channels; +}; + +// +// Routing Functions +// +void xy_yx_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) ; + +void xy_yx_no_express_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) ; + +void dor_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) ; + +void dor_no_express_cmesh( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) ; + +#endif diff --git a/src/intersim2/networks/dragonfly.cpp b/src/intersim2/networks/dragonfly.cpp new file mode 100644 index 0000000..b539cc6 --- /dev/null +++ b/src/intersim2/networks/dragonfly.cpp @@ -0,0 +1,575 @@ +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + Neither the name of the Stanford University 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <vector> +#include <sstream> + +#include "dragonfly.hpp" +#include "random_utils.hpp" +#include "misc_utils.hpp" +#include "globals.hpp" + +#define DRAGON_LATENCY + +int gP, gA, gG; + +//calculate the hop count between src and estination +int dragonflynew_hopcnt(int src, int dest) +{ + int hopcnt; + int dest_grp_ID, src_grp_ID; + int src_hopcnt, dest_hopcnt; + int src_intm, dest_intm; + int grp_output, dest_grp_output; + int grp_output_RID; + + int _grp_num_routers= gA; + int _grp_num_nodes =_grp_num_routers*gP; + + dest_grp_ID = int(dest/_grp_num_nodes); + src_grp_ID = int(src / _grp_num_nodes); + + //source and dest are in the same group, either 0-1 hop + if (dest_grp_ID == src_grp_ID) { + if ((int)(dest / gP) == (int)(src /gP)) + hopcnt = 0; + else + hopcnt = 1; + + } else { + //source and dest are in the same group + //find the number of hops in the source group + //find the number of hops in the dest group + if (src_grp_ID > dest_grp_ID) { + grp_output = dest_grp_ID; + dest_grp_output = src_grp_ID - 1; + } + else { + grp_output = dest_grp_ID - 1; + dest_grp_output = src_grp_ID; + } + grp_output_RID = ((int) (grp_output / (gP))) + src_grp_ID * _grp_num_routers; + src_intm = grp_output_RID * gP; + + grp_output_RID = ((int) (dest_grp_output / (gP))) + dest_grp_ID * _grp_num_routers; + dest_intm = grp_output_RID * gP; + + //hop count in source group + if ((int)( src_intm / gP) == (int)( src / gP ) ) + src_hopcnt = 0; + else + src_hopcnt = 1; + + //hop count in destination group + if ((int)( dest_intm / gP) == (int)( dest / gP ) ){ + dest_hopcnt = 0; + }else{ + dest_hopcnt = 1; + } + + //tally + hopcnt = src_hopcnt + 1 + dest_hopcnt; + } + + return hopcnt; +} + + +//packet output port based on the source, destination and current location +int dragonfly_port(int rID, int source, int dest){ + int _grp_num_routers= gA; + int _grp_num_nodes =_grp_num_routers*gP; + + int out_port = -1; + int grp_ID = int(rID / _grp_num_routers); + int dest_grp_ID = int(dest/_grp_num_nodes); + int grp_output=-1; + int grp_RID=-1; + int group_dest=-1; + + //which router within this group the packet needs to go to + if (dest_grp_ID == grp_ID) { + grp_RID = int(dest / gP); + } else { + if (grp_ID > dest_grp_ID) { + grp_output = dest_grp_ID; + } else { + grp_output = dest_grp_ID - 1; + } + grp_RID = int(grp_output /gP) + grp_ID * _grp_num_routers; + group_dest = grp_RID * gP; + } + + //At the last hop + if (dest >= rID*gP && dest < (rID+1)*gP) { + out_port = dest%gP; + } else if (grp_RID == rID) { + //At the optical link + out_port = gP + (gA-1) + grp_output %(gP); + } else { + //need to route within a group + assert(grp_RID!=-1); + + if (rID < grp_RID){ + out_port = (grp_RID % _grp_num_routers) - 1 + gP; + }else{ + out_port = (grp_RID % _grp_num_routers) + gP; + } + } + + assert(out_port!=-1); + return out_port; +} + + +DragonFlyNew::DragonFlyNew( const Configuration &config, const string & name ) : + Network( config, name ) +{ + + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + +void DragonFlyNew::_ComputeSize( const Configuration &config ) +{ + + // LIMITATION + // -- only one dimension between the group + // _n == # of dimensions within a group + // _p == # of processors within a router + // inter-group ports : _p + // terminal ports : _p + // intra-group ports : 2*_p - 1 + _p = config.GetInt( "k" ); // # of ports in each switch + _n = config.GetInt( "n" ); + + + assert(_n==1); + // dimension + + if (_n == 1) + _k = _p + _p + 2*_p - 1; + else + _k = _p + _p + 2*_p; + + + // FIX... + gK = _p; gN = _n; + + // with 1 dimension, total of 2p routers per group + // N = 2p * p * (2p^2 + 1) + // a = # of routers per group + // = 2p (if n = 1) + // = p^(n) (if n > 2) + // g = # of groups + // = a * p + 1 + // N = a * p * g; + + if (_n == 1) + _a = 2 * _p; + else + _a = powi(_p, _n); + + _g = _a * _p + 1; + _nodes = _a * _p * _g; + + _num_of_switch = _nodes / _p; + _channels = _num_of_switch * (_k - _p); + _size = _num_of_switch; + + + + gG = _g; + gP = _p; + gA = _a; + _grp_num_routers = gA; + _grp_num_nodes =_grp_num_routers*gP; + +} + +void DragonFlyNew::_BuildNet( const Configuration &config ) +{ + + int _output; + int _input; + int c; + int _dim_ID; + int _num_ports_per_switch; + int _dim_size; + + ostringstream router_name; + + + + cout << " Dragonfly " << endl; + cout << " p = " << _p << " n = " << _n << endl; + cout << " each switch - total radix = "<< _k << endl; + cout << " # of switches = "<< _num_of_switch << endl; + cout << " # of channels = "<< _channels << endl; + cout << " # of nodes ( size of network ) = " << _nodes << endl; + cout << " # of groups (_g) = " << _g << endl; + cout << " # of routers per group (_a) = " << _a << endl; + + for ( int node = 0; node < _num_of_switch; ++node ) { + // ID of the group + int grp_ID; + grp_ID = (int) (node/_a); + router_name << "router"; + + router_name << "_" << node ; + + _routers[node] = Router::NewRouter( config, this, router_name.str( ), + node, _k, _k ); + _timed_modules.push_back(_routers[node]); + + router_name.str(""); + + for ( int cnt = 0; cnt < _p; ++cnt ) { + c = _p * node + cnt; + _routers[node]->AddInputChannel( _inject[c], _inject_cred[c] ); + + } + + for ( int cnt = 0; cnt < _p; ++cnt ) { + c = _p * node + cnt; + _routers[node]->AddOutputChannel( _eject[c], _eject_cred[c] ); + + } + + // add OUPUT channels + // _k == # of processor per router + // need 2*_k routers --thus, + // 2_k-1 outputs channels within group + // _k-1 outputs for intra-group + + // + + if (_n > 1 ) { cout << " ERROR: n>1 dimension NOT supported yet... " << endl; exit(-1); } + + //******************************************** + // connect OUTPUT channels + //******************************************** + // add intra-group output channel + for ( int dim = 0; dim < _n; ++dim ) { + for ( int cnt = 0; cnt < (2*_p -1); ++cnt ) { + _output = (2*_p-1 + _p) * _n * node + (2*_p-1) * dim + cnt; + + _routers[node]->AddOutputChannel( _chan[_output], _chan_cred[_output] ); + +#ifdef DRAGON_LATENCY + _chan[_output]->SetLatency(10); + _chan_cred[_output]->SetLatency(10); +#endif + } + } + + // add inter-group output channel + + for ( int cnt = 0; cnt < _p; ++cnt ) { + _output = (2*_p-1 + _p) * node + (2*_p - 1) + cnt; + + // _chan[_output].global = true; + _routers[node]->AddOutputChannel( _chan[_output], _chan_cred[_output] ); +#ifdef DRAGON_LATENCY + _chan[_output]->SetLatency(100); + _chan_cred[_output]->SetLatency(100); +#endif + } + + + //******************************************** + // connect INPUT channels + //******************************************** + // # of non-local nodes + _num_ports_per_switch = (_k - _p); + + + // intra-group GROUP channels + for ( int dim = 0; dim < _n; ++dim ) { + + _dim_size = powi(_k,dim); + + _dim_ID = ((int) (node / ( powi(_p, dim)))); + + + + // NODE ID withing group + _dim_ID = node % _a; + + + + + for ( int cnt = 0; cnt < (2*_p-1); ++cnt ) { + + if ( cnt < _dim_ID) { + + _input = grp_ID * _num_ports_per_switch * _a - + (_dim_ID - cnt) * _num_ports_per_switch + + _dim_ID * _num_ports_per_switch + + (_dim_ID - 1); + } + else { + + _input = grp_ID * _num_ports_per_switch * _a + + _dim_ID * _num_ports_per_switch + + (cnt - _dim_ID + 1) * _num_ports_per_switch + + _dim_ID; + + } + + if (_input < 0) { + cout << " ERROR: _input less than zero " << endl; + exit(-1); + } + + + _routers[node]->AddInputChannel( _chan[_input], _chan_cred[_input] ); + } + } + + + // add INPUT channels -- "optical" channels connecting the groups + int _grp_num_routers; + int grp_output; + int grp_ID2; + + for ( int cnt = 0; cnt < _p; ++cnt ) { + // _dim_ID + grp_output = _dim_ID* _p + cnt; + + _grp_num_routers = powi(_k, _n-1); + grp_ID2 = (int) ((grp_ID - 1) / (_k - 1)); + + if ( grp_ID > grp_output) { + + _input = (grp_output) * _num_ports_per_switch * _a + // starting point of group + (_num_ports_per_switch - _p) * (int) ((grp_ID - 1) / _p) + // find the correct router within grp + (_num_ports_per_switch - _p) + // add offset within router + grp_ID - 1; + } else { + + _input = (grp_output + 1) * _num_ports_per_switch * _a + + (_num_ports_per_switch - _p) * (int) ((grp_ID) / _p) + // find the correct router within grp + (_num_ports_per_switch - _p) + + grp_ID; + } + + _routers[node]->AddInputChannel( _chan[_input], _chan_cred[_input] ); + } + + } + + cout<<"Done links"<<endl; +} + + +int DragonFlyNew::GetN( ) const +{ + return _n; +} + +int DragonFlyNew::GetK( ) const +{ + return _k; +} + +void DragonFlyNew::InsertRandomFaults( const Configuration &config ) +{ + +} + +double DragonFlyNew::Capacity( ) const +{ + return (double)_k / 8.0; +} + +void DragonFlyNew::RegisterRoutingFunctions(){ + + gRoutingFunctionMap["min_dragonflynew"] = &min_dragonflynew; + gRoutingFunctionMap["ugal_dragonflynew"] = &ugal_dragonflynew; +} + + +void min_dragonflynew( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + outputs->Clear( ); + + if(inject) { + int inject_vc= RandomInt(gNumVCs-1); + outputs->AddRange(-1, inject_vc, inject_vc); + return; + } + + int _grp_num_routers= gA; + + int dest = f->dest; + int rID = r->GetID(); + + int grp_ID = int(rID / _grp_num_routers); + int debug = f->watch; + int out_port = -1; + int out_vc = 0; + int dest_grp_ID=-1; + + if ( in_channel < gP ) { + out_vc = 0; + f->ph = 0; + if (dest_grp_ID == grp_ID) { + f->ph = 1; + } + } + + + out_port = dragonfly_port(rID, f->src, dest); + + //optical dateline + if (out_port >=gP + (gA-1)) { + f->ph = 1; + } + + out_vc = f->ph; + if (debug) + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << " through output port : " << out_port + << " out vc: " << out_vc << endl; + outputs->AddRange( out_port, out_vc, out_vc ); +} + + +//Basic adaptive routign algorithm for the dragonfly +void ugal_dragonflynew( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + //need 3 VCs for deadlock freedom + + assert(gNumVCs==3); + outputs->Clear( ); + if(inject) { + int inject_vc= RandomInt(gNumVCs-1); + outputs->AddRange(-1, inject_vc, inject_vc); + return; + } + + //this constant biases the adaptive decision toward minimum routing + //negative value woudl biases it towards nonminimum routing + int adaptive_threshold = 30; + + int _grp_num_routers= gA; + int _grp_num_nodes =_grp_num_routers*gP; + int _network_size = gA * gP * gG; + + + int dest = f->dest; + int rID = r->GetID(); + int grp_ID = (int) (rID / _grp_num_routers); + int dest_grp_ID = int(dest/_grp_num_nodes); + + int debug = f->watch; + int out_port = -1; + int out_vc = 0; + int min_queue_size, min_hopcnt; + int nonmin_queue_size, nonmin_hopcnt; + int intm_grp_ID; + int intm_rID; + + if(debug){ + cout<<"At router "<<rID<<endl; + } + int min_router_output, nonmin_router_output; + + //at the source router, make the adaptive routing decision + if ( in_channel < gP ) { + //dest are in the same group, only use minimum routing + if (dest_grp_ID == grp_ID) { + f->ph = 2; + } else { + //select a random node + f->intm =RandomInt(_network_size - 1); + intm_grp_ID = (int)(f->intm/_grp_num_nodes); + if (debug){ + cout<<"Intermediate node "<<f->intm<<" grp id "<<intm_grp_ID<<endl; + } + + //random intermediate are in the same group, use minimum routing + if(grp_ID == intm_grp_ID){ + f->ph = 1; + } else { + //congestion metrics using queue length, obtained by GetUsedCredit() + min_hopcnt = dragonflynew_hopcnt(f->src, f->dest); + min_router_output = dragonfly_port(rID, f->src, f->dest); + min_queue_size = max(r->GetUsedCredit(min_router_output), 0) ; + + + nonmin_hopcnt = dragonflynew_hopcnt(f->src, f->intm) + + dragonflynew_hopcnt(f->intm,f->dest); + nonmin_router_output = dragonfly_port(rID, f->src, f->intm); + nonmin_queue_size = max(r->GetUsedCredit(nonmin_router_output), 0); + + //congestion comparison, could use hopcnt instead of 1 and 2 + if ((1 * min_queue_size ) <= (2 * nonmin_queue_size)+adaptive_threshold ) { + if (debug) cout << " MINIMAL routing " << endl; + f->ph = 1; + } else { + f->ph = 0; + } + } + } + } + + //transition from nonminimal phase to minimal + if(f->ph==0){ + intm_rID= (int)(f->intm/gP); + if( rID == intm_rID){ + f->ph = 1; + } + } + + //port assignement based on the phase + if(f->ph == 0){ + out_port = dragonfly_port(rID, f->src, f->intm); + } else if(f->ph == 1){ + out_port = dragonfly_port(rID, f->src, f->dest); + } else if(f->ph == 2){ + out_port = dragonfly_port(rID, f->src, f->dest); + } else { + assert(false); + } + + //optical dateline + if (f->ph == 1 && out_port >=gP + (gA-1)) { + f->ph = 2; + } + + //vc assignemnt based on phase + out_vc = f->ph; + + outputs->AddRange( out_port, out_vc, out_vc ); +} diff --git a/src/intersim2/networks/dragonfly.hpp b/src/intersim2/networks/dragonfly.hpp new file mode 100644 index 0000000..02228ef --- /dev/null +++ b/src/intersim2/networks/dragonfly.hpp @@ -0,0 +1,74 @@ +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + + + +#ifndef _DragonFly_HPP_ +#define _DragonFly_HPP_ + +#include "network.hpp" +#include "routefunc.hpp" + +class DragonFlyNew : public Network { + + int _m; + int _n; + int _r; + int _k; + int _p, _a, _g; + int _radix; + int _net_size; + int _stageout; + int _numinput; + int _stages; + int _num_of_switch; + int _grp_num_routers; + int _grp_num_nodes; + + + void _ComputeSize( const Configuration &config ); + void _BuildNet( const Configuration &config ); + + + +public: + DragonFlyNew( const Configuration &config, const string & name ); + + int GetN( ) const; + int GetK( ) const; + + double Capacity( ) const; + static void RegisterRoutingFunctions(); + void InsertRandomFaults( const Configuration &config ); + +}; +int dragonfly_port(int rID, int source, int dest); + +void ugal_dragonflynew( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void min_dragonflynew( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); + +#endif diff --git a/src/intersim2/networks/fattree.cpp b/src/intersim2/networks/fattree.cpp new file mode 100644 index 0000000..81cd2b1 --- /dev/null +++ b/src/intersim2/networks/fattree.cpp @@ -0,0 +1,270 @@ +// $Id: fattree.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// FatTree +// +// Each level of the hierarchical indirect Network has +// k^(n-1) Routers. The Routers are organized such that +// each node has k descendents, and each parent is +// replicated k times. +// most routers has 2K ports, excep the top level has only K +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/06/26 22:50:48 $ +// $Id: fattree.cpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// + + +#include "booksim.hpp" +#include <vector> +#include <sstream> +#include <cmath> + +#include "fattree.hpp" +#include "misc_utils.hpp" + + + //#define FATTREE_DEBUG + +FatTree::FatTree( const Configuration& config,const string & name ) + : Network( config ,name) +{ + + + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); + +} + +void FatTree::_ComputeSize( const Configuration& config ) +{ + + _k = config.GetInt( "k" ); + _n = config.GetInt( "n" ); + + gK = _k; gN = _n; + + _nodes = powi( _k, _n ); + + //levels * routers_per_level + _size = _n * powi( _k , _n - 1 ); + + //(channels per level = k*routers_per_level* up/down) * (levels-1) + _channels = (2*_k * powi( _k , _n-1 ))*(_n-1); + + +} + + +void FatTree::RegisterRoutingFunctions() { + +} + +void FatTree::_BuildNet( const Configuration& config ) +{ + cout << "Fat Tree" << endl; + cout << " k = " << _k << " levels = " << _n << endl; + cout << " each switch - total radix = "<< 2*_k << endl; + cout << " # of switches = "<< _size << endl; + cout << " # of channels = "<< _channels << endl; + cout << " # of nodes ( size of network ) = " << _nodes << endl; + + + // Number of router positions at each depth of the network + const int nPos = powi( _k, _n-1); + + // + // Allocate Routers + // + ostringstream name; + int level, pos, id, degree, port; + for ( level = 0 ; level < _n ; ++level ) { + for ( pos = 0 ; pos < nPos ; ++pos ) { + + if ( level == 0 ) //top routers is zero + degree = _k; + else + degree = 2 * _k; + + id = level * nPos + pos; + + name.str(""); + name << "router_level" << level << "_" << pos; + Router * r = Router::NewRouter( config, this, name.str( ), id, + degree, degree ); + _Router( level, pos ) = r; + _timed_modules.push_back(r); + } + } + + // + // Connect Channels to Routers + // + + // + // Router Connection Rule: Output Ports <gK Move DOWN Network + // Output Ports >=gK Move UP Network + // Input Ports <gK from DOWN Network + // Input Ports >=gK from up Network + + // Connecting Injection & Ejection Channels + for ( pos = 0 ; pos < nPos ; ++pos ) { + for(int index = 0; index<_k; index++){ + int link = pos*_k + index; + _Router( _n-1, pos)->AddInputChannel( _inject[link], + _inject_cred[link]); + _Router( _n-1, pos)->AddOutputChannel( _eject[link], + _eject_cred[link]); + _inject[link]->SetLatency( 1 ); + _inject_cred[link]->SetLatency( 1 ); + _eject[link]->SetLatency( 1 ); + _eject_cred[link]->SetLatency( 1 ); + } + } + +#ifdef FATTREE_DEBUG + cout<<"\nAssigning output\n"; +#endif + + //channels are numbered sequentially from an output channel perspective + int chan_per_direction = (_k * powi( _k , _n-1 )); //up or down + int chan_per_level = 2*(_k * powi( _k , _n-1 )); //up+down + + //connect all down output channels + //level n-1's down channel are injection channels + for (level = 0; level<_n-1; level++){ + for ( pos = 0; pos < nPos; ++pos ) { + for ( port = 0; port < _k; ++port ) { + int link = (level*chan_per_level) + pos*_k + port; + _Router(level, pos)->AddOutputChannel( _chan[link], + _chan_cred[link] ); + _chan[link]->SetLatency( 1 ); + _chan_cred[link]->SetLatency( 1 ); +#ifdef FATTREE_DEBUG + cout<<_Router(level, pos)->Name()<<" " + <<"down output "<<port<<" " + <<"channel_id "<<link<<endl; +#endif + + } + } + } + //connect all up output channels + //level 0 has no up chnanels + for (level = 1; level<_n; level++){ + for ( pos = 0; pos < nPos; ++pos ) { + for ( port = 0; port < _k; ++port ) { + int link = (level*chan_per_level - chan_per_direction) + pos*_k + port ; + _Router(level, pos)->AddOutputChannel( _chan[link], + _chan_cred[link] ); + _chan[link]->SetLatency( 1 ); + _chan_cred[link]->SetLatency( 1 ); +#ifdef FATTREE_DEBUG + cout<<_Router(level, pos)->Name()<<" " + <<"up output "<<port<<" " + <<"channel_id "<<link<<endl; +#endif + } + } + } + +#ifdef FATTREE_DEBUG + cout<<"\nAssigning Input\n"; +#endif + + //connect all down input channels + for (level = 0; level<_n-1; level++){ + //input channel are numbered interleavely, the interleaev depends on level + int routers_per_neighborhood = powi(_k,_n-1-(level)); + int routers_per_branch = powi(_k,_n-1-(level+1)); + int level_offset = routers_per_neighborhood*_k; + for ( pos = 0; pos < nPos; ++pos ) { + int neighborhood = pos/routers_per_neighborhood; + int neighborhood_pos = pos%routers_per_neighborhood; + for ( port = 0; port < _k; ++port ) { + int link = + ((level+1)*chan_per_level - chan_per_direction) //which levellevel + +neighborhood*level_offset //region in level + +port*routers_per_branch*gK //sub region in region + +(neighborhood_pos)%routers_per_branch*gK //router in subregion + +(neighborhood_pos)/routers_per_branch; //port on router + + _Router(level, pos)->AddInputChannel( _chan[link], + _chan_cred[link] ); +#ifdef FATTREE_DEBUG + cout<<_Router(level, pos)->Name()<<" " + <<"down input "<<port<<" " + <<"channel_id "<<link<<endl; +#endif + } + } + } + + + //connect all up input channels + for (level = 1; level<_n; level++){ + //input channel are numbered interleavely, the interleaev depends on level + int routers_per_neighborhood = powi(_k,_n-1-(level-1)); + int routers_per_branch = powi(_k,_n-1-(level)); + int level_offset = routers_per_neighborhood*_k; + for ( pos = 0; pos < nPos; ++pos ) { + int neighborhood = pos/routers_per_neighborhood; + int neighborhood_pos = pos%routers_per_neighborhood; + for ( port = 0; port < _k; ++port ) { + int link = + ((level-1)*chan_per_level) //which levellevel + +neighborhood*level_offset //region in level + +port*routers_per_branch*gK //sub region in region + +(neighborhood_pos)%routers_per_branch*gK //router in subregion + +(neighborhood_pos)/routers_per_branch; //port on router + + _Router(level, pos)->AddInputChannel( _chan[link], + _chan_cred[link] ); +#ifdef FATTREE_DEBUG + cout<<_Router(level, pos)->Name()<<" " + <<"up input "<<port<<" " + <<"channel_id "<<link<<endl; +#endif + } + } + } +#ifdef FATTREE_DEBUG + cout<<"\nChannel assigned\n"; +#endif +} + +Router*& FatTree::_Router( int depth, int pos ) +{ + assert( depth < _n && pos < powi( _k, _n-1) ); + return _routers[depth * powi( _k, _n-1) + pos]; +} diff --git a/src/intersim2/networks/fattree.hpp b/src/intersim2/networks/fattree.hpp new file mode 100644 index 0000000..e537e5a --- /dev/null +++ b/src/intersim2/networks/fattree.hpp @@ -0,0 +1,76 @@ +// $Id: fattree.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// FatTree +// +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/06/26 22:49:23 $ +// $Id: fattree.hpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// + +#ifndef _FatTree_HPP_ +#define _FatTree_HPP_ + +#include "network.hpp" + +class FatTree : public Network { + + int _k; + int _n; + + + void _ComputeSize( const Configuration& config ); + void _BuildNet( const Configuration& config ); + + Router*& _Router( int depth, int pos ); + + int _mapSize; + int* _inputChannelMap; + int* _outputChannelMap; + int* _latencyMap; + + + +public: + + FatTree( const Configuration& config ,const string & name ); + static void RegisterRoutingFunctions() ; + + // + // Methods to Assit Routing Functions + // + static int PreferedPort( const Router* r, int index ); + +}; + +#endif diff --git a/src/intersim2/networks/flatfly_onchip.cpp b/src/intersim2/networks/flatfly_onchip.cpp new file mode 100644 index 0000000..fd17c1a --- /dev/null +++ b/src/intersim2/networks/flatfly_onchip.cpp @@ -0,0 +1,1331 @@ +// $Id: flatfly_onchip.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//Flattened butterfly simulator +//Created by John Kim +// +//Updated 11/6/2007 by Ted Jiang, now scales +//with any n such that N = K^3, k is a power of 2 +//however, the change restrict it to a 2D FBfly +// +//updated sometimes in december by Ted Jiang, now works for updat to 4 +//dimension. +// +//Updated 2/4/08 by Ted Jiang disabling partial networks +//change concentrations +// +//More update 3/31/08 to correctly assign the nodes to the routers +//UGAL now has added a "mapping" to account for this new assignment +//of the nodes to the routers +// +//Updated by mihelog 27 Aug to add progressive choice of intermediate destination. +//Also, half of the total vcs are used for non-minimal routing, others for minimal (for UGAL and valiant). + + +#include "booksim.hpp" +#include <vector> +#include <sstream> +#include <limits> +#include <cmath> +#include "flatfly_onchip.hpp" +#include "random_utils.hpp" +#include "misc_utils.hpp" +#include "globals.hpp" + + + +//#define DEBUG_FLATFLY + +static int _xcount; +static int _ycount; +static int _xrouter; +static int _yrouter; + +FlatFlyOnChip::FlatFlyOnChip( const Configuration &config, const string & name ) : + Network( config, name ) +{ + + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + +void FlatFlyOnChip::_ComputeSize( const Configuration &config ) +{ + _k = config.GetInt( "k" ); // # of routers per dimension + _n = config.GetInt( "n" ); // dimension + _c = config.GetInt( "c" ); //concentration, may be different from k + _r = _c + (_k-1)*_n ; // total radix of the switch ( # of inputs/outputs) + + //how many routers in the x or y direction + _xcount = config.GetInt("x"); + _ycount = config.GetInt("y"); + assert(_xcount == _ycount); + //configuration of hohw many clients in X and Y per router + _xrouter = config.GetInt("xr"); + _yrouter = config.GetInt("yr"); + assert(_xrouter == _yrouter); + gK = _k; + gN = _n; + gC = _c; + + assert(_c == _xrouter*_yrouter); + + _nodes = powi( _k, _n )*_c; //network size + + _num_of_switch = _nodes / _c; + _channels = _num_of_switch * (_r - _c); + _size = _num_of_switch; + +} + +void FlatFlyOnChip::_BuildNet( const Configuration &config ) +{ + int _output; + + ostringstream router_name; + + + if(gTrace){ + + cout<<"Setup Finished Router"<<endl; + + } + + //latency type, noc or conventional network + bool use_noc_latency; + use_noc_latency = (config.GetInt("use_noc_latency")==1); + + cout << " Flat Bufferfly " << endl; + cout << " k = " << _k << " n = " << _n << " c = "<<_c<< endl; + cout << " each switch - total radix = "<< _r << endl; + cout << " # of switches = "<< _num_of_switch << endl; + cout << " # of channels = "<< _channels << endl; + cout << " # of nodes ( size of network ) = " << _nodes << endl; + + for ( int node = 0; node < _num_of_switch; ++node ) { + + router_name << "router"; + router_name << "_" << node ; + + _routers[node] = Router::NewRouter( config, this, router_name.str( ), + node, _r, _r ); + _timed_modules.push_back(_routers[node]); + + +#ifdef DEBUG_FLATFLY + cout << " ======== router node : " << node << " ======== " << " router_" << router_name.str() << " router node # : " << node << endl; +#endif + + router_name.str(""); + + //****************************************************************** + // add inject/eject channels connected to the processor nodes + //****************************************************************** + + //as accurately model the length of these channels as possible + int yleng = -_yrouter/2; + int xleng = -_xrouter/2; + bool yodd = _yrouter%2==1; + bool xodd = _xrouter%2==1; + + int y_index = node/(_xcount); + int x_index = node%(_xcount); + //estimating distance from client to router + for (int y = 0; y < _yrouter ; y++) { + for (int x = 0; x < _xrouter ; x++) { + //Zero is a naughty number + if(yleng == 0 && !yodd){ + yleng++; + } + if(xleng == 0 && !xodd){ + xleng++; + } + int ileng = 1; //at least 1 away + //measure distance in the y direction + if(abs(yleng)>1){ + ileng+=(abs(yleng)-1); + } + //measure distance in the x direction + if(abs(xleng)>1){ + ileng+=(abs(xleng)-1); + } + //increment for the next client, add Y, if full, reset y add x + yleng++; + if(yleng>_yrouter/2){ + yleng= -_yrouter/2; + xleng++; + } + //adopted from the CMESH, the first node has 0,1,8,9 (as an example) + int link = (_xcount * _xrouter) * (_yrouter * y_index + y) + (_xrouter * x_index + x) ; + + if(use_noc_latency){ + _inject[link]->SetLatency(ileng); + _inject_cred[link]->SetLatency(ileng); + _eject[link] ->SetLatency(ileng); + _eject_cred[link]->SetLatency(ileng); + } else { + _inject[link]->SetLatency(1); + _inject_cred[link]->SetLatency(1); + _eject[link] ->SetLatency(1); + _eject_cred[link]->SetLatency(1); + } + _routers[node]->AddInputChannel( _inject[link], _inject_cred[link] ); + +#ifdef DEBUG_FLATFLY + cout << " Adding injection channel " << link << endl; +#endif + + _routers[node]->AddOutputChannel( _eject[link], _eject_cred[link] ); +#ifdef DEBUG_FLATFLY + cout << " Adding ejection channel " << link << endl; +#endif + } + } + } + //****************************************************************** + // add output inter-router channels + //****************************************************************** + + //for every router, in every dimension + for ( int node = 0; node < _num_of_switch; ++node ) { + for ( int dim = 0; dim < _n; ++dim ) { + + //locate itself in every dimension + int xcurr = node%_k; + int ycurr = (int)(node/_k); + int curr3 = node%(_k*_k); + int curr4 = (int)(node/(_k*_k)); + int curr5 = (int)(node/(_k*_k*_k));//mmm didn't mean to be racist + int curr6 = (node%(_k*_k*_k));//mmm didn't mean to be racist + + //for every other router in the dimension + for ( int cnt = 0; cnt < (_k ); ++cnt ) { + int other=0; //the other router that we are trying to connect + int offset = 0; //silly ness when node< other or when node>other + //if xdimension + if(dim == 0){ + other = ycurr * _k +cnt; + } else if (dim ==1){ + other = cnt * _k + xcurr; + if(_n==3){ + other+= curr4*_k*_k; + } + if(_n==4){ + curr4=((int)(node/(_k*_k)))%_k; + other+= curr4*_k*_k+curr5*_k*_k*_k; + } + }else if (dim ==2){ + other = cnt*_k*_k + curr3; + if(_n==4){ + other+= curr5*_k*_k*_k; + } + }else if (dim ==3){ + other = cnt*_k*_k*_k+curr6; + } + assert(dim < 4); + if(other == node){ +#ifdef DEBUG_FLATFLY + cout << "ignore channel : " << _output << " to node " << node <<" and "<<other<<endl; +#endif + continue; + } + //calculate channel length + int length = 0; + int oned = abs((node%_xcount)-(other%_xcount)); + int twod = abs(node/_xcount-other/_xcount); + length = _xrouter*oned + _yrouter *twod; + //oh the node<other silly ness + if(node<other){ + offset = -1; + } + //node, dimension, router within dimension. Good luck understanding this + _output = (_k-1) * _n * node + (_k-1) * dim + cnt+offset; + + +#ifdef DEBUG_FLATFLY + cout << "Adding channel : " << _output << " to node " << node <<" and "<<other<<" with length "<<length<<endl; +#endif + if(use_noc_latency){ + _chan[_output]->SetLatency(length); + _chan_cred[_output]->SetLatency(length); + } else { + _chan[_output]->SetLatency(1); + _chan_cred[_output]->SetLatency(1); + } + _routers[node]->AddOutputChannel( _chan[_output], _chan_cred[_output] ); + + _routers[other]->AddInputChannel( _chan[_output], _chan_cred[_output]); + + if(gTrace){ + cout<<"Link "<<_output<<" "<<node<<" "<<other<<" "<<length<<endl; + } + + } + } + } + if(gTrace){ + cout<<"Setup Finished Link"<<endl; + } +} + + +int FlatFlyOnChip::GetN( ) const +{ + return _n; +} + +int FlatFlyOnChip::GetK( ) const +{ + return _k; +} + +void FlatFlyOnChip::InsertRandomFaults( const Configuration &config ) +{ + +} + +double FlatFlyOnChip::Capacity( ) const +{ + return (double)_k / 8.0; +} + + +void FlatFlyOnChip::RegisterRoutingFunctions(){ + + + gRoutingFunctionMap["ran_min_flatfly"] = &min_flatfly; + gRoutingFunctionMap["adaptive_xyyx_flatfly"] = &adaptive_xyyx_flatfly; + gRoutingFunctionMap["xyyx_flatfly"] = &xyyx_flatfly; + gRoutingFunctionMap["valiant_flatfly"] = &valiant_flatfly; + gRoutingFunctionMap["ugal_flatfly"] = &ugal_flatfly_onchip; + gRoutingFunctionMap["ugal_pni_flatfly"] = &ugal_pni_flatfly_onchip; + gRoutingFunctionMap["ugal_xyyx_flatfly"] = &ugal_xyyx_flatfly_onchip; + +} + +//The initial XY or YX minimal routing direction is chosen adaptively +void adaptive_xyyx_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = flatfly_transformation(f->dest); + int targetr = (int)(dest/gC); + + if(targetr==r->GetID()){ //if we are at the final router, yay, output to client + out_port = dest % gC; + + } else { + + //each class must have at least 2 vcs assigned or else xy_yx will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + int out_port_xy = flatfly_outport(dest, r->GetID()); + int out_port_yx = flatfly_outport_yx(dest, r->GetID()); + + // Route order (XY or YX) determined when packet is injected + // into the network, adaptively + bool x_then_y; + if(in_channel < gC){ + int credit_xy = r->GetUsedCredit(out_port_xy); + int credit_yx = r->GetUsedCredit(out_port_yx); + if(credit_xy > credit_yx) { + x_then_y = false; + } else if(credit_xy < credit_yx) { + x_then_y = true; + } else { + x_then_y = (RandomInt(1) > 0); + } + } else { + x_then_y = (f->vc < (vcBegin + available_vcs)); + } + + if(x_then_y) { + out_port = out_port_xy; + vcEnd -= available_vcs; + } else { + out_port = out_port_yx; + vcBegin += available_vcs; + } + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + +//The initial XY or YX minimal routing direction is chosen randomly +void xyyx_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = flatfly_transformation(f->dest); + int targetr = (int)(dest/gC); + + if(targetr==r->GetID()){ //if we are at the final router, yay, output to client + out_port = dest % gC; + + } else { + + //each class must have at least 2 vcs assigned or else xy_yx will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + // randomly select dimension order at first hop + bool x_then_y = ((in_channel < gC) ? + (RandomInt(1) > 0) : + (f->vc < (vcBegin + available_vcs))); + + if(x_then_y) { + out_port = flatfly_outport(dest, r->GetID()); + vcEnd -= available_vcs; + } else { + out_port = flatfly_outport_yx(dest, r->GetID()); + vcBegin += available_vcs; + } + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + +int flatfly_outport_yx(int dest, int rID) { + int dest_rID = (int) (dest / gC); + int _dim = gN; + int output = -1, dID, sID; + + if(dest_rID==rID){ + return dest % gC; + } + + for (int d=_dim-1;d >= 0; d--) { + int power = powi(gK,d); + dID = int(dest_rID / power); + sID = int(rID / power); + if ( dID != sID ) { + output = gC + ((gK-1)*d) - 1; + if (dID > sID) { + output += dID; + } else { + output += dID + 1; + } + return output; + } + dest_rID = (int) (dest_rID %power); + rID = (int) (rID %power); + } + if (output == -1) { + cout << " ERROR ---- FLATFLY_OUTPORT function : output not found yx" << endl; + exit(-1); + } + return -1; +} + +void valiant_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + if ( in_channel < gC ){ + f->ph = 0; + f->intm = RandomInt( powi( gK, gN )*gC-1); + } + + int intm = flatfly_transformation(f->intm); + int dest = flatfly_transformation(f->dest); + + if((int)(intm/gC) == r->GetID() || (int)(dest/gC)== r->GetID()){ + f->ph = 1; + } + + if(f->ph == 0) { + out_port = flatfly_outport(intm, r->GetID()); + } else { + assert(f->ph == 1); + out_port = flatfly_outport(dest, r->GetID()); + } + + if((int)(dest/gC) != r->GetID()) { + + //each class must have at least 2 vcs assigned or else valiant valiant will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + if(f->ph == 0) { + vcEnd -= available_vcs; + } else { + // If routing to final destination use the second half of the VCs. + assert(f->ph == 1); + vcBegin += available_vcs; + } + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + +void min_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = flatfly_transformation(f->dest); + int targetr= (int)(dest/gC); + //int xdest = ((int)(dest/gC)) % gK; + //int xcurr = ((r->GetID())) % gK; + + //int ydest = ((int)(dest/gC)) / gK; + //int ycurr = ((r->GetID())) / gK; + + if(targetr==r->GetID()){ //if we are at the final router, yay, output to client + out_port = dest % gC; + } else{ //else select a dimension at random + out_port = flatfly_outport(dest, r->GetID()); + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + +//=============================================================^M +// route UGAL in the flattened butterfly +//=============================================================^M + + +//same as ugal except uses xyyx routing +void ugal_xyyx_flatfly_onchip( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = flatfly_transformation(f->dest); + + int rID = r->GetID(); + int _concentration = gC; + int found; + int debug = 0; + int tmp_out_port, _ran_intm; + int _min_hop, _nonmin_hop, _min_queucnt, _nonmin_queucnt; + int threshold = 2; + + + if ( in_channel < gC ){ + if(gTrace){ + cout<<"New Flit "<<f->src<<endl; + } + f->ph = 0; + } + + if(gTrace){ + int load = 0; + cout<<"Router "<<rID<<endl; + cout<<"Input Channel "<<in_channel<<endl; + //need to modify router to report the buffere depth + load +=r->GetBufferOccupancy(in_channel); + cout<<"Rload "<<load<<endl; + } + + if (debug){ + cout << " FLIT ID: " << f->id << " Router: " << rID << " routing from src : " << f->src << " to dest : " << dest << " f->ph: " <<f->ph << " intm: " << f->intm << endl; + } + // f->ph == 0 ==> make initial global adaptive decision + // f->ph == 1 ==> route nonminimaly to random intermediate node + // f->ph == 2 ==> route minimally to destination + + found = 0; + + if (f->ph == 1){ + dest = f->intm; + } + + if (dest >= rID*_concentration && dest < (rID+1)*_concentration) { + if (f->ph == 1) { + f->ph = 2; + dest = flatfly_transformation(f->dest); + if (debug) cout << " done routing to intermediate "; + } + else { + found = 1; + out_port = dest % gC; + if (debug) cout << " final routing to destination "; + } + } + + if (!found) { + + int const xy_available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(xy_available_vcs > 0); + + // randomly select dimension order at first hop + bool x_then_y = ((in_channel < gC) ? + (RandomInt(1) > 0) : + (f->vc < (vcBegin + xy_available_vcs))); + + if (f->ph == 0) { + //find the min port and min distance + _min_hop = find_distance(flatfly_transformation(f->src),dest); + if(x_then_y){ + tmp_out_port = flatfly_outport(dest, rID); + } else { + tmp_out_port = flatfly_outport_yx(dest, rID); + } + if (f->watch){ + cout << " MIN tmp_out_port: " << tmp_out_port; + } + //sum over all vcs of that port + _min_queucnt = r->GetUsedCredit(tmp_out_port); + + //find the nonmin router, nonmin port, nonmin count + _ran_intm = find_ran_intm(flatfly_transformation(f->src), dest); + _nonmin_hop = find_distance(flatfly_transformation(f->src),_ran_intm) + find_distance(_ran_intm, dest); + if(x_then_y){ + tmp_out_port = flatfly_outport(_ran_intm, rID); + } else { + tmp_out_port = flatfly_outport_yx(_ran_intm, rID); + } + + if (f->watch){ + cout << " NONMIN tmp_out_port: " << tmp_out_port << endl; + } + if (_ran_intm >= rID*_concentration && _ran_intm < (rID+1)*_concentration) { + _nonmin_queucnt = numeric_limits<int>::max(); + } else { + _nonmin_queucnt = r->GetUsedCredit(tmp_out_port); + } + + if (debug){ + cout << " _min_hop " << _min_hop << " _min_queucnt: " <<_min_queucnt << " _nonmin_hop: " << _nonmin_hop << " _nonmin_queucnt :" << _nonmin_queucnt << endl; + } + + if (_min_hop * _min_queucnt <= _nonmin_hop * _nonmin_queucnt +threshold) { + + if (debug) cout << " Route MINIMALLY " << endl; + f->ph = 2; + } else { + // route non-minimally + if (debug) { cout << " Route NONMINIMALLY int node: " <<_ran_intm << endl; } + f->ph = 1; + f->intm = _ran_intm; + dest = f->intm; + if (dest >= rID*_concentration && dest < (rID+1)*_concentration) { + f->ph = 2; + dest = flatfly_transformation(f->dest); + } + } + } + + //dest here should be == intm if ph==1, or dest == dest if ph == 2 + if(x_then_y){ + out_port = flatfly_outport(dest, rID); + if(out_port >= gC) { + vcEnd -= xy_available_vcs; + } + } else { + out_port = flatfly_outport_yx(dest, rID); + if(out_port >= gC) { + vcBegin += xy_available_vcs; + } + } + + // if we haven't reached our destination, restrict VCs appropriately to avoid routing deadlock + if(out_port >= gC) { + + int const ph_available_vcs = xy_available_vcs / 2; + assert(ph_available_vcs > 0); + + if(f->ph == 1) { + vcEnd -= ph_available_vcs; + } else { + assert(f->ph == 2); + vcBegin += ph_available_vcs; + } + } + + found = 1; + } + + if (!found) { + cout << " ERROR: output not found in routing. " << endl; + cout << *f; exit (-1); + } + + if (out_port >= gN*(gK-1) + gC) { + cout << " ERROR: output port too big! " << endl; + cout << " OUTPUT select: " << out_port << endl; + cout << " router radix: " << gN*(gK-1) + gK << endl; + exit (-1); + } + + if (debug) cout << " through output port : " << out_port << endl; + if(gTrace){cout<<"Outport "<<out_port<<endl;cout<<"Stop Mark"<<endl;} + + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + + + +//ugal now uses modified comparison, modefied getcredit +void ugal_flatfly_onchip( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = flatfly_transformation(f->dest); + + int rID = r->GetID(); + int _concentration = gC; + int found; + int debug = 0; + int tmp_out_port, _ran_intm; + int _min_hop, _nonmin_hop, _min_queucnt, _nonmin_queucnt; + int threshold = 2; + + if ( in_channel < gC ){ + if(gTrace){ + cout<<"New Flit "<<f->src<<endl; + } + f->ph = 0; + } + + if(gTrace){ + int load = 0; + cout<<"Router "<<rID<<endl; + cout<<"Input Channel "<<in_channel<<endl; + //need to modify router to report the buffere depth + load +=r->GetBufferOccupancy(in_channel); + cout<<"Rload "<<load<<endl; + } + + if (debug){ + cout << " FLIT ID: " << f->id << " Router: " << rID << " routing from src : " << f->src << " to dest : " << dest << " f->ph: " <<f->ph << " intm: " << f->intm << endl; + } + // f->ph == 0 ==> make initial global adaptive decision + // f->ph == 1 ==> route nonminimaly to random intermediate node + // f->ph == 2 ==> route minimally to destination + + found = 0; + + if (f->ph == 1){ + dest = f->intm; + } + + + if (dest >= rID*_concentration && dest < (rID+1)*_concentration) { + + if (f->ph == 1) { + f->ph = 2; + dest = flatfly_transformation(f->dest); + if (debug) cout << " done routing to intermediate "; + } + else { + found = 1; + out_port = dest % gC; + if (debug) cout << " final routing to destination "; + } + } + + if (!found) { + + if (f->ph == 0) { + _min_hop = find_distance(flatfly_transformation(f->src),dest); + _ran_intm = find_ran_intm(flatfly_transformation(f->src), dest); + tmp_out_port = flatfly_outport(dest, rID); + if (f->watch){ + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << " MIN tmp_out_port: " << tmp_out_port; + } + + _min_queucnt = r->GetUsedCredit(tmp_out_port); + + _nonmin_hop = find_distance(flatfly_transformation(f->src),_ran_intm) + find_distance(_ran_intm, dest); + tmp_out_port = flatfly_outport(_ran_intm, rID); + + if (f->watch){ + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << " NONMIN tmp_out_port: " << tmp_out_port << endl; + } + if (_ran_intm >= rID*_concentration && _ran_intm < (rID+1)*_concentration) { + _nonmin_queucnt = numeric_limits<int>::max(); + } else { + _nonmin_queucnt = r->GetUsedCredit(tmp_out_port); + } + + if (debug){ + cout << " _min_hop " << _min_hop << " _min_queucnt: " <<_min_queucnt << " _nonmin_hop: " << _nonmin_hop << " _nonmin_queucnt :" << _nonmin_queucnt << endl; + } + + if (_min_hop * _min_queucnt <= _nonmin_hop * _nonmin_queucnt +threshold) { + + if (debug) cout << " Route MINIMALLY " << endl; + f->ph = 2; + } else { + // route non-minimally + if (debug) { cout << " Route NONMINIMALLY int node: " <<_ran_intm << endl; } + f->ph = 1; + f->intm = _ran_intm; + dest = f->intm; + if (dest >= rID*_concentration && dest < (rID+1)*_concentration) { + f->ph = 2; + dest = flatfly_transformation(f->dest); + } + } + } + + // find minimal correct dimension to route through + out_port = flatfly_outport(dest, rID); + + // if we haven't reached our destination, restrict VCs appropriately to avoid routing deadlock + if(out_port >= gC) { + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + if(f->ph == 1) { + vcEnd -= available_vcs; + } else { + assert(f->ph == 2); + vcBegin += available_vcs; + } + } + + found = 1; + } + + if (!found) { + cout << " ERROR: output not found in routing. " << endl; + cout << *f; exit (-1); + } + + if (out_port >= gN*(gK-1) + gC) { + cout << " ERROR: output port too big! " << endl; + cout << " OUTPUT select: " << out_port << endl; + cout << " router radix: " << gN*(gK-1) + gK << endl; + exit (-1); + } + + if (debug) cout << " through output port : " << out_port << endl; + if(gTrace) { + cout<<"Outport "<<out_port<<endl; + cout<<"Stop Mark"<<endl; + } + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + + +// partially non-interfering (i.e., packets ordered by hash of destination) UGAL +void ugal_pni_flatfly_onchip( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + // ( Traffic Class , Routing Order ) -> Virtual Channel Range + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = flatfly_transformation(f->dest); + + int rID = r->GetID(); + int _concentration = gC; + int found; + int debug = 0; + int tmp_out_port, _ran_intm; + int _min_hop, _nonmin_hop, _min_queucnt, _nonmin_queucnt; + int threshold = 2; + + if ( in_channel < gC ){ + if(gTrace){ + cout<<"New Flit "<<f->src<<endl; + } + f->ph = 0; + } + + if(gTrace){ + int load = 0; + cout<<"Router "<<rID<<endl; + cout<<"Input Channel "<<in_channel<<endl; + //need to modify router to report the buffere depth + load +=r->GetBufferOccupancy(in_channel); + cout<<"Rload "<<load<<endl; + } + + if (debug){ + cout << " FLIT ID: " << f->id << " Router: " << rID << " routing from src : " << f->src << " to dest : " << dest << " f->ph: " <<f->ph << " intm: " << f->intm << endl; + } + // f->ph == 0 ==> make initial global adaptive decision + // f->ph == 1 ==> route nonminimaly to random intermediate node + // f->ph == 2 ==> route minimally to destination + + found = 0; + + if (f->ph == 1){ + dest = f->intm; + } + + + if (dest >= rID*_concentration && dest < (rID+1)*_concentration) { + + if (f->ph == 1) { + f->ph = 2; + dest = flatfly_transformation(f->dest); + if (debug) cout << " done routing to intermediate "; + } + else { + found = 1; + out_port = dest % gC; + if (debug) cout << " final routing to destination "; + } + } + + if (!found) { + + if (f->ph == 0) { + _min_hop = find_distance(flatfly_transformation(f->src),dest); + _ran_intm = find_ran_intm(flatfly_transformation(f->src), dest); + tmp_out_port = flatfly_outport(dest, rID); + if (f->watch){ + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << " MIN tmp_out_port: " << tmp_out_port; + } + + _min_queucnt = r->GetUsedCredit(tmp_out_port); + + _nonmin_hop = find_distance(flatfly_transformation(f->src),_ran_intm) + find_distance(_ran_intm, dest); + tmp_out_port = flatfly_outport(_ran_intm, rID); + + if (f->watch){ + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << " NONMIN tmp_out_port: " << tmp_out_port << endl; + } + if (_ran_intm >= rID*_concentration && _ran_intm < (rID+1)*_concentration) { + _nonmin_queucnt = numeric_limits<int>::max(); + } else { + _nonmin_queucnt = r->GetUsedCredit(tmp_out_port); + } + + if (debug){ + cout << " _min_hop " << _min_hop << " _min_queucnt: " <<_min_queucnt << " _nonmin_hop: " << _nonmin_hop << " _nonmin_queucnt :" << _nonmin_queucnt << endl; + } + + if (_min_hop * _min_queucnt <= _nonmin_hop * _nonmin_queucnt +threshold) { + + if (debug) cout << " Route MINIMALLY " << endl; + f->ph = 2; + } else { + // route non-minimally + if (debug) { cout << " Route NONMINIMALLY int node: " <<_ran_intm << endl; } + f->ph = 1; + f->intm = _ran_intm; + dest = f->intm; + if (dest >= rID*_concentration && dest < (rID+1)*_concentration) { + f->ph = 2; + dest = flatfly_transformation(f->dest); + } + } + } + + // find minimal correct dimension to route through + out_port = flatfly_outport(dest, rID); + + // if we haven't reached our destination, restrict VCs appropriately to avoid routing deadlock + if(out_port >= gC) { + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + if(f->ph == 1) { + vcEnd -= available_vcs; + } else { + assert(f->ph == 2); + vcBegin += available_vcs; + } + } + + found = 1; + } + + if (!found) { + cout << " ERROR: output not found in routing. " << endl; + cout << *f; exit (-1); + } + + if (out_port >= gN*(gK-1) + gC) { + cout << " ERROR: output port too big! " << endl; + cout << " OUTPUT select: " << out_port << endl; + cout << " router radix: " << gN*(gK-1) + gK << endl; + exit (-1); + } + + if (debug) cout << " through output port : " << out_port << endl; + if(gTrace) { + cout<<"Outport "<<out_port<<endl; + cout<<"Stop Mark"<<endl; + } + } + + if(inject || (out_port >= gC)) { + + // NOTE: for "proper" flattened butterfly configurations (i.e., ones + // derived from flattening an actual butterfly), gK and gC are the same! + assert(gK == gC); + + assert(inject ? (f->ph == -1) : (f->ph == 1 || f->ph == 2)); + + int next_coord = flatfly_transformation(f->dest); + if(inject) { + next_coord /= gC; + next_coord %= gK; + } else { + int next_dim = (out_port - gC) / (gK - 1) + 1; + if(next_dim == gN) { + next_coord %= gC; + } else { + next_coord /= gC; + for(int d = 0; d < next_dim; ++d) { + next_coord /= gK; + } + next_coord %= gK; + } + } + assert(next_coord >= 0 && next_coord < gK); + int vcs_per_dest = (vcEnd - vcBegin + 1) / gK; + assert(vcs_per_dest > 0); + vcBegin += next_coord * vcs_per_dest; + vcEnd = vcBegin + vcs_per_dest - 1; + } + + outputs->Clear( ); + + outputs->AddRange( out_port , vcBegin, vcEnd ); +} + + +//=============================================================^M +// UGAL : calculate distance (hop cnt) between src and destination +//=============================================================^M +int find_distance (int src, int dest) { + int dist = 0; + int _dim = gN; + int _dim_size; + + int src_tmp= (int) src / gC; + int dest_tmp = (int) dest / gC; + int src_id, dest_id; + + // cout << " HOP CNT between src: " << src << " dest: " << dest; + for (int d=0;d < _dim; d++) { + _dim_size = powi(gK, d )*gC; + //if ((int)(src / _dim_size) != (int)(dest / _dim_size)) + // dist++; + src_id = src_tmp % gK; + dest_id = dest_tmp % gK; + if (src_id != dest_id) + dist++; + src_tmp = (int) (src_tmp / gK); + dest_tmp = (int) (dest_tmp / gK); + } + + // cout << " : " << dist << endl; + + return dist; +} + +//=============================================================^M +// UGAL : find random node for load balancing +//=============================================================^M +int find_ran_intm (int src, int dest) { + int _dim = gN; + int _dim_size; + int _ran_dest = 0; + int debug = 0; + + if (debug) + cout << " INTM node for src: " << src << " dest: " <<dest << endl; + + src = (int) (src / gC); + dest = (int) (dest / gC); + + _ran_dest = RandomInt(gC - 1); + if (debug) cout << " ............ _ran_dest : " << _ran_dest << endl; + for (int d=0;d < _dim; d++) { + + _dim_size = powi(gK, d)*gC; + if ((src % gK) == (dest % gK)) { + _ran_dest += (src % gK) * _dim_size; + if (debug) + cout << " share same dimension : " << d << " int node : " << _ran_dest << " src ID : " << src % gK << endl; + } else { + // src and dest are in the same dimension "d" + 1 + // ==> thus generate a random destination within + _ran_dest += RandomInt(gK - 1) * _dim_size; + if (debug) + cout << " different dimension : " << d << " int node : " << _ran_dest << " _dim_size: " << _dim_size << endl; + } + src = (int) (src / gK); + dest = (int) (dest / gK); + } + + if (debug) cout << " intermediate destination NODE: " << _ran_dest << endl; + return _ran_dest; +} + + + +//============================================================= +// UGAL : calculated minimum distance output port for flatfly +// given the dimension and destination +//============================================================= +// starting from DIM 0 (x first) +int flatfly_outport(int dest, int rID) { + int dest_rID = (int) (dest / gC); + int _dim = gN; + int output = -1, dID, sID; + + if(dest_rID==rID){ + return dest % gC; + } + + + for (int d=0;d < _dim; d++) { + dID = (dest_rID % gK); + sID = (rID % gK); + if ( dID != sID ) { + output = gC + ((gK-1)*d) - 1; + if (dID > sID) { + + output += dID; + } else { + output += dID + 1; + } + + return output; + } + dest_rID = (int) (dest_rID / gK); + rID = (int) (rID / gK); + } + if (output == -1) { + cout << " ERROR ---- FLATFLY_OUTPORT function : output not found " << endl; + exit(-1); + } + return -1; +} + +int flatfly_transformation(int dest){ + //the magic of destination transformation + + //destination transformation, translate how the nodes are actually arranged + //to the easier way of routing + //this transformation only support 64 nodes + + //cout<<"ORiginal destination "<<dest<<endl; + //router in the x direction = find which column, and then mod by cY to find + //which horizontal router + int horizontal = (dest%(_xcount*_xrouter))/(_xrouter); + int horizontal_rem = (dest%(_xcount*_xrouter))%(_xrouter); + //router in the y direction = find which row, and then divided by cX to find + //vertical router + int vertical = (dest/(_xcount*_xrouter))/(_yrouter); + int vertical_rem = (dest/(_xcount*_xrouter))%(_yrouter); + //transform the destination to as if node0 was 0,1,2,3 and so forth + dest = (vertical*_xcount + horizontal)*gC+_xrouter*vertical_rem+horizontal_rem; + //cout<<"Transformed destination "<<dest<<endl<<endl; + return dest; +} diff --git a/src/intersim2/networks/flatfly_onchip.hpp b/src/intersim2/networks/flatfly_onchip.hpp new file mode 100644 index 0000000..2f164be --- /dev/null +++ b/src/intersim2/networks/flatfly_onchip.hpp @@ -0,0 +1,88 @@ +// $Id: flatfly_onchip.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _FlatFlyOnChip_HPP_ +#define _FlatFlyOnChip_HPP_ + +#include "network.hpp" + +#include "routefunc.hpp" +#include <cassert> + + +class FlatFlyOnChip : public Network { + + int _m; + int _n; + int _r; + int _k; + int _c; + int _radix; + int _net_size; + int _stageout; + int _numinput; + int _stages; + int _num_of_switch; + + void _ComputeSize( const Configuration &config ); + void _BuildNet( const Configuration &config ); + + int _OutChannel( int stage, int addr, int port, int outputs ) const; + int _InChannel( int stage, int addr, int port ) const; + +public: + FlatFlyOnChip( const Configuration &config, const string & name ); + + int GetN( ) const; + int GetK( ) const; + + static void RegisterRoutingFunctions() ; + double Capacity( ) const; + void InsertRandomFaults( const Configuration &config ); +}; +void adaptive_xyyx_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void xyyx_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void min_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void ugal_xyyx_flatfly_onchip( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void ugal_flatfly_onchip( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void ugal_pni_flatfly_onchip( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); +void valiant_flatfly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ); + +int find_distance (int src, int dest); +int find_ran_intm (int src, int dest); +int flatfly_outport(int dest, int rID); +int flatfly_transformation(int dest); +int flatfly_outport_yx(int dest, int rID); + +#endif diff --git a/src/intersim2/networks/fly.cpp b/src/intersim2/networks/fly.cpp new file mode 100644 index 0000000..8e0bdd7 --- /dev/null +++ b/src/intersim2/networks/fly.cpp @@ -0,0 +1,162 @@ +// $Id: fly.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <vector> +#include <sstream> + +#include "fly.hpp" +#include "misc_utils.hpp" + +//#define DEBUG_FLY + +KNFly::KNFly( const Configuration &config, const string & name ) : +Network( config, name ) +{ + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + +void KNFly::_ComputeSize( const Configuration &config ) +{ + _k = config.GetInt( "k" ); + _n = config.GetInt( "n" ); + + gK = _k; gN = _n; + + _nodes = powi( _k, _n ); + + // n stages of k^(n-1) k x k switches + _size = _n*powi( _k, _n-1 ); + + // n-1 sets of wiring between the stages + _channels = (_n-1)*_nodes; +} + +void KNFly::_BuildNet( const Configuration &config ) +{ + ostringstream router_name; + + int per_stage = powi( _k, _n-1 ); + + int node = 0; + int c; + + for ( int stage = 0; stage < _n; ++stage ) { + for ( int addr = 0; addr < per_stage; ++addr ) { + + router_name << "router_" << stage << "_" << addr; + _routers[node] = Router::NewRouter( config, this, router_name.str( ), + node, _k, _k ); + _timed_modules.push_back(_routers[node]); + router_name.str(""); + +#ifdef DEBUG_FLY + cout << "connecting node " << node << " to:" << endl; +#endif + + for ( int port = 0; port < _k; ++port ) { + // Input connections + if ( stage == 0 ) { + c = addr*_k + port; + _routers[node]->AddInputChannel( _inject[c], _inject_cred[c] ); +#ifdef DEBUG_FLY + cout << " injection channel " << c << endl; +#endif + } else { + c = _InChannel( stage, addr, port ); + _routers[node]->AddInputChannel( _chan[c], _chan_cred[c] ); + _chan[c]->SetLatency( 1 ); + +#ifdef DEBUG_FLY + cout << " input channel " << c << endl; +#endif + } + + // Output connections + if ( stage == _n - 1 ) { + c = addr*_k + port; + _routers[node]->AddOutputChannel( _eject[c], _eject_cred[c] ); +#ifdef DEBUG_FLY + cout << " ejection channel " << c << endl; +#endif + } else { + c = _OutChannel( stage, addr, port ); + _routers[node]->AddOutputChannel( _chan[c], _chan_cred[c] ); +#ifdef DEBUG_FLY + cout << " output channel " << c << endl; +#endif + } + } + + ++node; + } + } +} + +int KNFly::_OutChannel( int stage, int addr, int port ) const +{ + return stage*_nodes + addr*_k + port; +} + +int KNFly::_InChannel( int stage, int addr, int port ) const +{ + int in_addr; + int in_port; + + // Channels are between {node,port} + // { d_{n-1} ... d_{n-stage} ... d_0 } and + // { d_{n-1} ... d_0 ... d_{n-stage} } + + int shift = powi( _k, _n-stage-1 ); + + int last_digit = port; + int zero_digit = ( addr / shift ) % _k; + + // swap zero and last digit to get first node's address + in_addr = addr - zero_digit*shift + last_digit*shift; + in_port = zero_digit; + + return (stage-1)*_nodes + in_addr*_k + in_port; +} + +int KNFly::GetN( ) const +{ + return _n; +} + +int KNFly::GetK( ) const +{ + return _k; +} + +double KNFly::Capacity( ) const +{ + return 1.0; +} + diff --git a/src/intersim2/networks/fly.hpp b/src/intersim2/networks/fly.hpp new file mode 100644 index 0000000..c32062f --- /dev/null +++ b/src/intersim2/networks/fly.hpp @@ -0,0 +1,53 @@ +// $Id: fly.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _FLY_HPP_ +#define _FLY_HPP_ + +#include "network.hpp" + +class KNFly : public Network { + + int _k; + int _n; + + void _ComputeSize( const Configuration &config ); + void _BuildNet( const Configuration &config ); + + int _OutChannel( int stage, int addr, int port ) const; + int _InChannel( int stage, int addr, int port ) const; + +public: + KNFly( const Configuration &config, const string & name ); + + int GetN( ) const; + int GetK( ) const; + static void RegisterRoutingFunctions(){}; + double Capacity( ) const; +}; + +#endif diff --git a/src/intersim2/networks/kncube.cpp b/src/intersim2/networks/kncube.cpp new file mode 100644 index 0000000..6915f22 --- /dev/null +++ b/src/intersim2/networks/kncube.cpp @@ -0,0 +1,319 @@ +// $Id: kncube.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*kn.cpp + * + *Meshs, cube, torus + * + */ + +#include "booksim.hpp" +#include <vector> +#include <sstream> +#include "kncube.hpp" +#include "random_utils.hpp" +#include "misc_utils.hpp" + //#include "iq_router.hpp" + + +KNCube::KNCube( const Configuration &config, const string & name, bool mesh ) : +Network( config, name ) +{ + _mesh = mesh; + + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + +void KNCube::_ComputeSize( const Configuration &config ) +{ + _k = config.GetInt( "k" ); + _n = config.GetInt( "n" ); + + gK = _k; gN = _n; + _size = powi( _k, _n ); + _channels = 2*_n*_size; + + _nodes = _size; +} + +void KNCube::RegisterRoutingFunctions() { + +} +void KNCube::_BuildNet( const Configuration &config ) +{ + int left_node; + int right_node; + + int right_input; + int left_input; + + int right_output; + int left_output; + + ostringstream router_name; + + //latency type, noc or conventional network + bool use_noc_latency; + use_noc_latency = (config.GetInt("use_noc_latency")==1); + + for ( int node = 0; node < _size; ++node ) { + + router_name << "router"; + + if ( _k > 1 ) { + for ( int dim_offset = _size / _k; dim_offset >= 1; dim_offset /= _k ) { + router_name << "_" << ( node / dim_offset ) % _k; + } + } + + _routers[node] = Router::NewRouter( config, this, router_name.str( ), + node, 2*_n + 1, 2*_n + 1 ); + _timed_modules.push_back(_routers[node]); + + router_name.str(""); + + for ( int dim = 0; dim < _n; ++dim ) { + + //find the neighbor + left_node = _LeftNode( node, dim ); + right_node = _RightNode( node, dim ); + + // + // Current (N)ode + // (L)eft node + // (R)ight node + // + // L--->N<---R + // L<---N--->R + // + + // torus channel is longer due to wrap around + int latency = _mesh ? 1 : 2 ; + + //get the input channel number + right_input = _LeftChannel( right_node, dim ); + left_input = _RightChannel( left_node, dim ); + + //add the input channel + _routers[node]->AddInputChannel( _chan[right_input], _chan_cred[right_input] ); + _routers[node]->AddInputChannel( _chan[left_input], _chan_cred[left_input] ); + + //set input channel latency + if(use_noc_latency){ + _chan[right_input]->SetLatency( latency ); + _chan[left_input]->SetLatency( latency ); + _chan_cred[right_input]->SetLatency( latency ); + _chan_cred[left_input]->SetLatency( latency ); + } else { + _chan[left_input]->SetLatency( 1 ); + _chan_cred[right_input]->SetLatency( 1 ); + _chan_cred[left_input]->SetLatency( 1 ); + _chan[right_input]->SetLatency( 1 ); + } + //get the output channel number + right_output = _RightChannel( node, dim ); + left_output = _LeftChannel( node, dim ); + + //add the output channel + _routers[node]->AddOutputChannel( _chan[right_output], _chan_cred[right_output] ); + _routers[node]->AddOutputChannel( _chan[left_output], _chan_cred[left_output] ); + + //set output channel latency + if(use_noc_latency){ + _chan[right_output]->SetLatency( latency ); + _chan[left_output]->SetLatency( latency ); + _chan_cred[right_output]->SetLatency( latency ); + _chan_cred[left_output]->SetLatency( latency ); + } else { + _chan[right_output]->SetLatency( 1 ); + _chan[left_output]->SetLatency( 1 ); + _chan_cred[right_output]->SetLatency( 1 ); + _chan_cred[left_output]->SetLatency( 1 ); + + } + } + //injection and ejection channel, always 1 latency + _routers[node]->AddInputChannel( _inject[node], _inject_cred[node] ); + _routers[node]->AddOutputChannel( _eject[node], _eject_cred[node] ); + _inject[node]->SetLatency( 1 ); + _eject[node]->SetLatency( 1 ); + } +} + +int KNCube::_LeftChannel( int node, int dim ) +{ + // The base channel for a node is 2*_n*node + int base = 2*_n*node; + // The offset for a left channel is 2*dim + 1 + int off = 2*dim + 1; + + return ( base + off ); +} + +int KNCube::_RightChannel( int node, int dim ) +{ + // The base channel for a node is 2*_n*node + int base = 2*_n*node; + // The offset for a right channel is 2*dim + int off = 2*dim; + return ( base + off ); +} + +int KNCube::_LeftNode( int node, int dim ) +{ + int k_to_dim = powi( _k, dim ); + int loc_in_dim = ( node / k_to_dim ) % _k; + int left_node; + // if at the left edge of the dimension, wraparound + if ( loc_in_dim == 0 ) { + left_node = node + (_k-1)*k_to_dim; + } else { + left_node = node - k_to_dim; + } + + return left_node; +} + +int KNCube::_RightNode( int node, int dim ) +{ + int k_to_dim = powi( _k, dim ); + int loc_in_dim = ( node / k_to_dim ) % _k; + int right_node; + // if at the right edge of the dimension, wraparound + if ( loc_in_dim == ( _k-1 ) ) { + right_node = node - (_k-1)*k_to_dim; + } else { + right_node = node + k_to_dim; + } + + return right_node; +} + +int KNCube::GetN( ) const +{ + return _n; +} + +int KNCube::GetK( ) const +{ + return _k; +} + +/*legacy, not sure how this fits into the own scheme of things*/ +void KNCube::InsertRandomFaults( const Configuration &config ) +{ + int num_fails; + unsigned long prev_seed; + + int node, chan; + int i, j, t, n, c; + bool available; + + bool edge; + + num_fails = config.GetInt( "link_failures" ); + + if ( num_fails ) { + prev_seed = RandomIntLong( ); + RandomSeed( config.GetInt( "fail_seed" ) ); + + vector<bool> fail_nodes(_size); + + for ( i = 0; i < _size; ++i ) { + node = i; + + // edge test + edge = false; + for ( n = 0; n < _n; ++n ) { + if ( ( ( node % _k ) == 0 ) || + ( ( node % _k ) == _k - 1 ) ) { + edge = true; + } + node /= _k; + } + + if ( edge ) { + fail_nodes[i] = true; + } else { + fail_nodes[i] = false; + } + } + + for ( i = 0; i < num_fails; ++i ) { + j = RandomInt( _size - 1 ); + available = false; + + for ( t = 0; ( t < _size ) && (!available); ++t ) { + node = ( j + t ) % _size; + + if ( !fail_nodes[node] ) { + // check neighbors + c = RandomInt( 2*_n - 1 ); + + for ( n = 0; ( n < 2*_n ) && (!available); ++n ) { + chan = ( n + c ) % 2*_n; + + if ( chan % 1 ) { + available = fail_nodes[_LeftNode( node, chan/2 )]; + } else { + available = fail_nodes[_RightNode( node, chan/2 )]; + } + } + } + + if ( !available ) { + cout << "skipping " << node << endl; + } + } + + if ( t == _size ) { + Error( "Could not find another possible fault channel" ); + } + + + OutChannelFault( node, chan ); + fail_nodes[node] = true; + + for ( n = 0; ( n < _n ) && available ; ++n ) { + fail_nodes[_LeftNode( node, n )] = true; + fail_nodes[_RightNode( node, n )] = true; + } + + cout << "failure at node " << node << ", channel " + << chan << endl; + } + + RandomSeed( prev_seed ); + } +} + +double KNCube::Capacity( ) const +{ + return (double)_k / ( _mesh ? 8.0 : 4.0 ); +} diff --git a/src/intersim2/networks/kncube.hpp b/src/intersim2/networks/kncube.hpp new file mode 100644 index 0000000..b3ca1ca --- /dev/null +++ b/src/intersim2/networks/kncube.hpp @@ -0,0 +1,62 @@ +// $Id: kncube.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _KNCUBE_HPP_ +#define _KNCUBE_HPP_ + +#include "network.hpp" + +class KNCube : public Network { + + bool _mesh; + + int _k; + int _n; + + void _ComputeSize( const Configuration &config ); + void _BuildNet( const Configuration &config ); + + int _LeftChannel( int node, int dim ); + int _RightChannel( int node, int dim ); + + int _LeftNode( int node, int dim ); + int _RightNode( int node, int dim ); + +public: + KNCube( const Configuration &config, const string & name, bool mesh ); + static void RegisterRoutingFunctions(); + + int GetN( ) const; + int GetK( ) const; + + double Capacity( ) const; + + void InsertRandomFaults( const Configuration &config ); + +}; + +#endif diff --git a/src/intersim2/networks/network.cpp b/src/intersim2/networks/network.cpp new file mode 100644 index 0000000..2909429 --- /dev/null +++ b/src/intersim2/networks/network.cpp @@ -0,0 +1,290 @@ +// $Id: network.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*network.cpp + * + *This class is the basis of the entire network, it contains, all the routers + *channels in the network, and is extended by all the network topologies + * + */ + +#include <cassert> +#include <sstream> + +#include "booksim.hpp" +#include "network.hpp" + +#include "kncube.hpp" +#include "fly.hpp" +#include "cmesh.hpp" +#include "flatfly_onchip.hpp" +#include "qtree.hpp" +#include "tree4.hpp" +#include "fattree.hpp" +#include "anynet.hpp" +#include "dragonfly.hpp" + + +Network::Network( const Configuration &config, const string & name ) : + TimedModule( 0, name ) +{ + _size = -1; + _nodes = -1; + _channels = -1; + _classes = config.GetInt("classes"); +} + +Network::~Network( ) +{ + for ( int r = 0; r < _size; ++r ) { + if ( _routers[r] ) delete _routers[r]; + } + for ( int s = 0; s < _nodes; ++s ) { + if ( _inject[s] ) delete _inject[s]; + if ( _inject_cred[s] ) delete _inject_cred[s]; + } + for ( int d = 0; d < _nodes; ++d ) { + if ( _eject[d] ) delete _eject[d]; + if ( _eject_cred[d] ) delete _eject_cred[d]; + } + for ( int c = 0; c < _channels; ++c ) { + if ( _chan[c] ) delete _chan[c]; + if ( _chan_cred[c] ) delete _chan_cred[c]; + } +} + +Network * Network::New(const Configuration & config, const string & name) +{ + const string topo = config.GetStr( "topology" ); + Network * n = NULL; + if ( topo == "torus" ) { + KNCube::RegisterRoutingFunctions() ; + n = new KNCube( config, name, false ); + } else if ( topo == "mesh" ) { + KNCube::RegisterRoutingFunctions() ; + n = new KNCube( config, name, true ); + } else if ( topo == "cmesh" ) { + CMesh::RegisterRoutingFunctions() ; + n = new CMesh( config, name ); + } else if ( topo == "fly" ) { + KNFly::RegisterRoutingFunctions() ; + n = new KNFly( config, name ); + } else if ( topo == "qtree" ) { + QTree::RegisterRoutingFunctions() ; + n = new QTree( config, name ); + } else if ( topo == "tree4" ) { + Tree4::RegisterRoutingFunctions() ; + n = new Tree4( config, name ); + } else if ( topo == "fattree" ) { + FatTree::RegisterRoutingFunctions() ; + n = new FatTree( config, name ); + } else if ( topo == "flatfly" ) { + FlatFlyOnChip::RegisterRoutingFunctions() ; + n = new FlatFlyOnChip( config, name ); + } else if ( topo == "anynet"){ + AnyNet::RegisterRoutingFunctions() ; + n = new AnyNet(config, name); + } else if ( topo == "dragonflynew"){ + DragonFlyNew::RegisterRoutingFunctions() ; + n = new DragonFlyNew(config, name); + } else { + cerr << "Unknown topology: " << topo << endl; + } + + /*legacy code that insert random faults in the networks + *not sure how to use this + */ + if ( n && ( config.GetInt( "link_failures" ) > 0 ) ) { + n->InsertRandomFaults( config ); + } + return n; +} + +void Network::_Alloc( ) +{ + assert( ( _size != -1 ) && + ( _nodes != -1 ) && + ( _channels != -1 ) ); + + _routers.resize(_size); + gNodes = _nodes; + + /*booksim used arrays of flits as the channels which makes have capacity of + *one. To simulate channel latency, flitchannel class has been added + *which are fifos with depth = channel latency and each cycle the channel + *shifts by one + *credit channels are the necessary counter part + */ + _inject.resize(_nodes); + _inject_cred.resize(_nodes); + for ( int s = 0; s < _nodes; ++s ) { + ostringstream name; + name << Name() << "_fchan_ingress" << s; + _inject[s] = new FlitChannel(this, name.str(), _classes); + _inject[s]->SetSource(NULL, s); + _timed_modules.push_back(_inject[s]); + name.str(""); + name << Name() << "_cchan_ingress" << s; + _inject_cred[s] = new CreditChannel(this, name.str()); + _timed_modules.push_back(_inject_cred[s]); + } + _eject.resize(_nodes); + _eject_cred.resize(_nodes); + for ( int d = 0; d < _nodes; ++d ) { + ostringstream name; + name << Name() << "_fchan_egress" << d; + _eject[d] = new FlitChannel(this, name.str(), _classes); + _eject[d]->SetSink(NULL, d); + _timed_modules.push_back(_eject[d]); + name.str(""); + name << Name() << "_cchan_egress" << d; + _eject_cred[d] = new CreditChannel(this, name.str()); + _timed_modules.push_back(_eject_cred[d]); + } + _chan.resize(_channels); + _chan_cred.resize(_channels); + for ( int c = 0; c < _channels; ++c ) { + ostringstream name; + name << Name() << "_fchan_" << c; + _chan[c] = new FlitChannel(this, name.str(), _classes); + _timed_modules.push_back(_chan[c]); + name.str(""); + name << Name() << "_cchan_" << c; + _chan_cred[c] = new CreditChannel(this, name.str()); + _timed_modules.push_back(_chan_cred[c]); + } +} + +void Network::ReadInputs( ) +{ + for(deque<TimedModule *>::const_iterator iter = _timed_modules.begin(); + iter != _timed_modules.end(); + ++iter) { + (*iter)->ReadInputs( ); + } +} + +void Network::Evaluate( ) +{ + for(deque<TimedModule *>::const_iterator iter = _timed_modules.begin(); + iter != _timed_modules.end(); + ++iter) { + (*iter)->Evaluate( ); + } +} + +void Network::WriteOutputs( ) +{ + for(deque<TimedModule *>::const_iterator iter = _timed_modules.begin(); + iter != _timed_modules.end(); + ++iter) { + (*iter)->WriteOutputs( ); + } +} + +void Network::WriteFlit( Flit *f, int source ) +{ + assert( ( source >= 0 ) && ( source < _nodes ) ); + _inject[source]->Send(f); +} + +Flit *Network::ReadFlit( int dest ) +{ + assert( ( dest >= 0 ) && ( dest < _nodes ) ); + return _eject[dest]->Receive(); +} + +void Network::WriteCredit( Credit *c, int dest ) +{ + assert( ( dest >= 0 ) && ( dest < _nodes ) ); + _eject_cred[dest]->Send(c); +} + +Credit *Network::ReadCredit( int source ) +{ + assert( ( source >= 0 ) && ( source < _nodes ) ); + return _inject_cred[source]->Receive(); +} + +void Network::InsertRandomFaults( const Configuration &config ) +{ + Error( "InsertRandomFaults not implemented for this topology!" ); +} + +void Network::OutChannelFault( int r, int c, bool fault ) +{ + assert( ( r >= 0 ) && ( r < _size ) ); + _routers[r]->OutChannelFault( c, fault ); +} + +double Network::Capacity( ) const +{ + return 1.0; +} + +/* this function can be heavily modified to display any information + * neceesary of the network, by default, call display on each router + * and display the channel utilization rate + */ +void Network::Display( ostream & os ) const +{ + for ( int r = 0; r < _size; ++r ) { + _routers[r]->Display( os ); + } +} + +void Network::DumpChannelMap( ostream & os, string const & prefix ) const +{ + os << prefix << "source_router,source_port,dest_router,dest_port" << endl; + for(int c = 0; c < _nodes; ++c) + os << prefix + << "-1," + << _inject[c]->GetSourcePort() << ',' + << _inject[c]->GetSink()->GetID() << ',' + << _inject[c]->GetSinkPort() << endl; + for(int c = 0; c < _channels; ++c) + os << prefix + << _chan[c]->GetSource()->GetID() << ',' + << _chan[c]->GetSourcePort() << ',' + << _chan[c]->GetSink()->GetID() << ',' + << _chan[c]->GetSinkPort() << endl; + for(int c = 0; c < _nodes; ++c) + os << prefix + << _eject[c]->GetSource()->GetID() << ',' + << _eject[c]->GetSourcePort() << ',' + << "-1," + << _eject[c]->GetSinkPort() << endl; +} + +void Network::DumpNodeMap( ostream & os, string const & prefix ) const +{ + os << prefix << "source_router,dest_router" << endl; + for(int s = 0; s < _nodes; ++s) + os << prefix + << _eject[s]->GetSource()->GetID() << ',' + << _inject[s]->GetSink()->GetID() << endl; +} diff --git a/src/intersim2/networks/network.hpp b/src/intersim2/networks/network.hpp new file mode 100644 index 0000000..fcf0253 --- /dev/null +++ b/src/intersim2/networks/network.hpp @@ -0,0 +1,118 @@ +// $Id: network.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _NETWORK_HPP_ +#define _NETWORK_HPP_ + +#include <vector> +#include <deque> + +#include "module.hpp" +#include "flit.hpp" +#include "credit.hpp" +#include "router.hpp" +#include "module.hpp" +#include "timed_module.hpp" +#include "flitchannel.hpp" +#include "channel.hpp" +#include "config_utils.hpp" +#include "globals.hpp" + +typedef Channel<Credit> CreditChannel; + + +class Network : public TimedModule { +protected: + + int _size; + int _nodes; + int _channels; + int _classes; + + vector<Router *> _routers; + + vector<FlitChannel *> _inject; + vector<CreditChannel *> _inject_cred; + + vector<FlitChannel *> _eject; + vector<CreditChannel *> _eject_cred; + + vector<FlitChannel *> _chan; + vector<CreditChannel *> _chan_cred; + + deque<TimedModule *> _timed_modules; + + virtual void _ComputeSize( const Configuration &config ) = 0; + virtual void _BuildNet( const Configuration &config ) = 0; + + void _Alloc( ); + +public: + Network( const Configuration &config, const string & name ); + virtual ~Network( ); + + static Network *New( const Configuration &config, const string & name ); + + virtual void WriteFlit( Flit *f, int source ); + virtual Flit *ReadFlit( int dest ); + + virtual void WriteCredit( Credit *c, int dest ); + virtual Credit *ReadCredit( int source ); + + inline int NumNodes( ) const {return _nodes;} + + virtual void InsertRandomFaults( const Configuration &config ); + void OutChannelFault( int r, int c, bool fault = true ); + + virtual double Capacity( ) const; + + virtual void ReadInputs( ); + virtual void Evaluate( ); + virtual void WriteOutputs( ); + + void Display( ostream & os = cout ) const; + void DumpChannelMap( ostream & os = cout, string const & prefix = "" ) const; + void DumpNodeMap( ostream & os = cout, string const & prefix = "" ) const; + + int NumChannels() const {return _channels;} + const vector<FlitChannel *> & GetInject() {return _inject;} + FlitChannel * GetInject(int index) {return _inject[index];} + const vector<CreditChannel *> & GetInjectCred() {return _inject_cred;} + CreditChannel * GetInjectCred(int index) {return _inject_cred[index];} + const vector<FlitChannel *> & GetEject(){return _eject;} + FlitChannel * GetEject(int index) {return _eject[index];} + const vector<CreditChannel *> & GetEjectCred(){return _eject_cred;} + CreditChannel * GetEjectCred(int index) {return _eject_cred[index];} + const vector<FlitChannel *> & GetChannels(){return _chan;} + const vector<CreditChannel *> & GetChannelsCred(){return _chan_cred;} + const vector<Router *> & GetRouters(){return _routers;} + Router * GetRouter(int index) {return _routers[index];} + int NumRouters() const {return _size;} +}; + +#endif + diff --git a/src/intersim2/networks/qtree.cpp b/src/intersim2/networks/qtree.cpp new file mode 100644 index 0000000..7214947 --- /dev/null +++ b/src/intersim2/networks/qtree.cpp @@ -0,0 +1,187 @@ +// $Id: qtree.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// QTree: A Quad-Tree Indirect Network. +// +// +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/05/17 17:14:07 $ +// $Id: qtree.cpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// + +#include "booksim.hpp" +#include <vector> +#include <sstream> +#include "qtree.hpp" +#include "misc_utils.hpp" + +QTree::QTree( const Configuration& config, const string & name ) +: Network ( config, name ) +{ + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + + +void QTree::_ComputeSize( const Configuration& config ) +{ + + _k = config.GetInt( "k" ); + _n = config.GetInt( "n" ); + + assert( _k == 4 && _n == 3 ); + + gK = _k; gN = _n; + + _nodes = powi( _k, _n ); + + _size = 0; + for (int i = 0; i < _n; i++) + _size += powi( _k, i ); + + _channels = 0; + for (int j = 1; j < _n; j++) + _channels += 2 * powi( _k, j ); + +} + +void QTree::RegisterRoutingFunctions(){ + +} + +void QTree::_BuildNet( const Configuration& config ) +{ + + ostringstream routerName; + int h, r, pos, port; + + for (h = 0; h < _n; h++) { + for (pos = 0 ; pos < powi( _k, h ) ; ++pos ) { + + int id = h * 256 + pos; + r = _RouterIndex( h, pos ); + + routerName << "router_" << h << "_" << pos; + + int d = ( h == 0 ) ? _k : _k + 1; + _routers[r] = Router::NewRouter( config, this, + routerName.str( ), + id, d, d); + _timed_modules.push_back(_routers[r]); + routerName.str(""); + } + } + + // Injection & Ejection Channels + for ( pos = 0 ; pos < powi( _k, _n-1 ) ; ++pos ) { + r = _RouterIndex( _n-1, pos ); + for ( port = 0 ; port < _k ; port++ ) { + + _routers[r]->AddInputChannel( _inject[_k*pos+port], + _inject_cred[_k*pos+port]); + + _routers[r]->AddOutputChannel( _eject[_k*pos+port], + _eject_cred[_k*pos+port]); + } + } + + int c; + for ( h = 0 ; h < _n ; ++h ) { + for ( pos = 0 ; pos < powi( _k, h ) ; ++pos ) { + for ( port = 0 ; port < _k ; port++ ) { + + r = _RouterIndex( h, pos ); + + if ( h < _n-1 ) { + // Channels to Children Nodes + c = _InputIndex( h , pos, port ); + _routers[r]->AddInputChannel( _chan[c], + _chan_cred[c] ); + + c = _OutputIndex( h, pos, port ); + _routers[r]->AddOutputChannel( _chan[c], + _chan_cred[c] ); + + } + } + if ( h > 0 ) { + // Channels to Parent Nodes + c = _OutputIndex( h - 1, pos / _k, pos % _k ); + _routers[r]->AddInputChannel( _chan[c], + _chan_cred[c] ); + + c = _InputIndex( h - 1, pos / _k, pos % _k ); + _routers[r]->AddOutputChannel( _chan[c], + _chan_cred[c]); + } + } + } +} + +int QTree::_RouterIndex( int height, int pos ) +{ + int r = 0; + for ( int h = 0; h < height; h++ ) + r += powi( _k, h ); + return (r + pos); +} + +int QTree::_InputIndex( int height, int pos, int port ) +{ + assert( height >= 0 && height < powi( _k,_n-1 ) ); + int c = 0; + for ( int h = 0; h < height; h++) + c += powi( _k, h+1 ); + return ( c + _k * pos + port ); +} + +int QTree::_OutputIndex( int height, int pos, int port ) +{ + assert( height >= 0 && height < powi( _k,_n-1 ) ); + int c = _channels / 2; + for ( int h = 0; h < height; h++) + c += powi( _k, h+1 ); + return ( c + _k * pos + port ); +} + + +int QTree::HeightFromID( int id ) +{ + return id / 256; +} + +int QTree::PosFromID( int id ) +{ + return id % 256; +} diff --git a/src/intersim2/networks/qtree.hpp b/src/intersim2/networks/qtree.hpp new file mode 100644 index 0000000..0a31a92 --- /dev/null +++ b/src/intersim2/networks/qtree.hpp @@ -0,0 +1,69 @@ +// $Id: qtree.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// QTree: A Quad-Tree Indirect Network. +// +// +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/05/17 17:14:07 $ +// $Id: qtree.hpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// + +#ifndef _QTREE_HPP_ +#define _QTREE_HPP_ +#include <cassert> +#include "network.hpp" + +class QTree : public Network { + + int _k; + int _n; + + void _ComputeSize( const Configuration& config ); + void _BuildNet( const Configuration& config ); + + int _RouterIndex( int height, int pos ); + int _InputIndex( int height, int pos, int port ); + int _OutputIndex( int height, int pos, int port ); + +public: + + QTree( const Configuration& config, const string & name ); + static void RegisterRoutingFunctions() ; + + static int HeightFromID( int id ); + static int PosFromID( int id ); + +}; + +#endif diff --git a/src/intersim2/networks/tree4.cpp b/src/intersim2/networks/tree4.cpp new file mode 100644 index 0000000..5650fe4 --- /dev/null +++ b/src/intersim2/networks/tree4.cpp @@ -0,0 +1,289 @@ +// $Id: tree4.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// Tree4: Network with 64 Terminal Nodes arranged in a tree topology +// with 4 routers at the root of the tree +// +// Level 0 : 4 8 x 8 Routers (8 Descending Links per Router) +// Level 1 : 8 8 x 8 Routers (4 Descending Links per Router) +// Level 2 : 16 6 x 6 Routers (4 Descending Links per Router) +// Level 3 : 64 Terminal Nodes +// +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/06/26 22:49:23 $ +// $Id: tree4.cpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// + +#include "booksim.hpp" +#include <vector> +#include <sstream> +#include <cmath> + +#include "tree4.hpp" +#include "misc_utils.hpp" + +Tree4::Tree4( const Configuration& config, const string & name ) +: Network ( config, name ) +{ + _ComputeSize( config ); + _Alloc( ); + _BuildNet( config ); +} + +void Tree4::_ComputeSize( const Configuration& config ) +{ + int h; + + _k = config.GetInt( "k" ); + assert(_k == 4); + _n = config.GetInt( "n" ); + assert(_n == 3); + + gK = _k; gN = _n; + + _nodes = powi( _k, _n ); + + _size = 0; + for ( h = 0; h < _n; ++h ) + _size += (4 >> h) * powi( _k, h ); + + _channels = 2 // Two Channels per Connection + * ( 2 * powi( _k, 1) ) // Number of Middle Routers + * ( 2 * _k ); // Connectivity of Middle Routers +} + +void Tree4::RegisterRoutingFunctions(){ + +} + +void Tree4::_BuildNet( const Configuration& config ) +{ + + // + // Allocate Routers + // + ostringstream name; + int h, pos, nPos, degree, id; + + for ( h = 0; h < _n; h++ ) { + nPos = (4 >> h) * powi( _k, h ); + for ( pos = 0; pos < nPos; ++pos) { + if ( h < _n-1 ) + degree = 8; + else + degree = 6; + + name.str(""); + name << "router_" << h << "_" << pos; + id = h * powi( _k, _n-1 ) + pos; + Router * r = Router::NewRouter( config, this, name.str( ), + id, degree, degree ); + _Router( h, pos ) = r; + _timed_modules.push_back(r); + } + } + + // + // Connect Channels to Routers + // + int pp, pc; + // + // Connection Rule: Output Ports 0:3 Move DOWN Network + // Output Ports 4:7 Move UP Network + // + + // Injection & Ejection Channels + nPos = powi( _k, _n - 1 ); + for ( pos = 0 ; pos < nPos ; ++pos ) { + for ( int port = 0 ; port < _k ; ++port ) { + + _Router( _n-1, pos)->AddInputChannel( _inject[_k*pos+port], + _inject_cred[_k*pos+port]); + + + _inject[_k*pos+port]->SetLatency( 1 ); + _inject_cred[_k*pos+port]->SetLatency( 1 ); + + _Router( _n-1, pos)->AddOutputChannel( _eject[_k*pos+port], + _eject_cred[_k*pos+port]); + + _eject[_k*pos+port]->SetLatency( 1 ); + _eject_cred[_k*pos+port]->SetLatency( 1 ); + + } + } + + // Connections between h = 1 and h = 2 Levels + int c = 0; + nPos = 2 * powi( _k, 1 ); + for ( pos = 0; pos < nPos; ++pos ) { + for ( int port = 0; port < _k; ++port ) { + + pp = pos; + pc = _k * ( pos / 2 ) + port; + + // cout << "connecting (1,"<<pp<<") <-> (2,"<<pc<<")"<<endl; + + _Router( 1, pp)->AddOutputChannel( _chan[c], _chan_cred[c] ); + _Router( 2, pc)->AddInputChannel( _chan[c], _chan_cred[c] ); + + //_chan[c]->SetLatency( L ); + //_chan_cred[c]->SetLatency( L ); + + _chan[c]->SetLatency( 1 ); + _chan_cred[c]->SetLatency( 1 ); + + c++; + + _Router(1, pp)->AddInputChannel( _chan[c], _chan_cred[c] ); + _Router(2, pc)->AddOutputChannel( _chan[c], _chan_cred[c] ); + + //_chan[c]->SetLatency( L ); + //_chan_cred[c]->SetLatency( L ); + _chan[c]->SetLatency( 1 ); + _chan_cred[c]->SetLatency( 1 ); + + c++; + } + } + + // Connections between h = 0 and h = 1 Levels + nPos = 4 * powi( _k, 0 ); + for ( pos = 0; pos < nPos; ++pos ) { + for ( int port = 0; port < 2 * _k; ++port ) { + pp = pos; + pc = port; + + // cout << "connecting (0,"<<pp<<") <-> (1,"<<pc<<")"<<endl; + + _Router(0, pp)->AddOutputChannel( _chan[c], _chan_cred[c] ); + _Router(1, pc)->AddInputChannel( _chan[c], _chan_cred[c] ); + + // _chan[c]->SetLatency( L ); + //_chan_cred[c]->SetLatency( L ); + _chan[c]->SetLatency( 1 ); + _chan_cred[c]->SetLatency( 1 ); + + c++; + + _Router(0, pp)->AddInputChannel( _chan[c], _chan_cred[c] ); + _Router(1, pc)->AddOutputChannel( _chan[c], _chan_cred[c] ); + + // _chan[c]->SetLatency( L ); + // _chan_cred[c]->SetLatency( L ); + _chan[c]->SetLatency( 1 ); + _chan_cred[c]->SetLatency( 1 ); + c++; + } + } + + // cout << "Used " << c << " of " << _channels << " channels" << endl; + +} + +Router*& Tree4::_Router( int height, int pos ) +{ + assert( height < _n ); + assert( pos < (4 >> height) * powi( _k, height) ); + + int i = 0; + for ( int h = 0; h < height; ++h ) + i += (4 >> h) * powi( _k, h ); + return _routers[i+pos]; + +} + +int Tree4::_WireLatency( int height1, int pos1, int height2, int pos2 ) +{ + int heightChild, heightParent, posChild, posParent; + + int L; + + if (height1 < height2) { + heightChild = height2; + posChild = pos2; + heightParent = height1; + posParent = pos1; + } else { + heightChild = height1; + posChild = pos1; + heightParent = height2; + posParent = pos2; + } + + int _length_d2_d1 = 2 ; + int _length_d1_d0_0 = 2 ; + int _length_d1_d0_1 = 2 ; + int _length_d1_d0_2 = 6 ; + int _length_d1_d0_3 = 6 ; + + assert( heightChild == heightParent+1 ); + + // We must decrement the delays by one to account for how the + // simulator interprets the specified delay (with 0 indicating one + // cycle of delay). + + if ( heightChild == 2 ) + L = _length_d2_d1; + else { + if ( posChild == 0 || posChild == 6 ) + switch ( posParent ) { + case 0: L =_length_d1_d0_0; break; + case 1: L =_length_d1_d0_1; break; + case 2: L =_length_d1_d0_2; break; + case 3: L =_length_d1_d0_3; break; + } + if ( posChild == 1 || posChild == 7 ) + switch ( posParent ) { + case 0: L =_length_d1_d0_3; break; + case 1: L =_length_d1_d0_2; break; + case 2: L =_length_d1_d0_1; break; + case 3: L =_length_d1_d0_0; break; + } + if ( posChild == 2 || posChild == 4 ) + switch ( posParent ) { + case 0: L = _length_d1_d0_0; break; + case 1: L = _length_d1_d0_1; break; + case 2: L = _length_d1_d0_2; break; + case 3: L = _length_d1_d0_3; break; + } + if ( posChild == 3|| posChild == 5 ) + switch ( posParent ) { + case 0: L =_length_d1_d0_3; break; + case 1: L =_length_d1_d0_2; break; + case 2: L =_length_d1_d0_1; break; + case 3: L =_length_d1_d0_0; break; + } + } + return L; +} diff --git a/src/intersim2/networks/tree4.hpp b/src/intersim2/networks/tree4.hpp new file mode 100644 index 0000000..76e5be8 --- /dev/null +++ b/src/intersim2/networks/tree4.hpp @@ -0,0 +1,72 @@ +// $Id: tree4.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +//////////////////////////////////////////////////////////////////////// +// +// Tree4: Network with 64 Terminal Nodes arranged in a tree topology +// with 4 routers at the root of the tree +// +//////////////////////////////////////////////////////////////////////// +// +// RCS Information: +// $Author: jbalfour $ +// $Date: 2007/06/26 22:49:23 $ +// $Id: tree4.hpp 5188 2012-08-30 00:31:31Z dub $ +// +//////////////////////////////////////////////////////////////////////// + +#ifndef _TREE4_HPP_ +#define _TREE4_HPP_ +#include <cassert> +#include "network.hpp" + +class Tree4 : public Network { + + int _k; + int _n; + + int _channelWidth; + + void _ComputeSize( const Configuration& config ); + void _BuildNet( const Configuration& config ); + + + Router*& _Router( int height, int pos ); + + int _WireLatency( int height1, int pos1, int height2, int pos2 ); + +public: + + Tree4( const Configuration& config, const string & name ); + static void RegisterRoutingFunctions() ; + + static int HeightFromID( int id ); + static int PosFromID( int id ); + static int SpeedUp( int height ); +}; + +#endif diff --git a/src/intersim2/outputset.cpp b/src/intersim2/outputset.cpp new file mode 100644 index 0000000..1b50a1a --- /dev/null +++ b/src/intersim2/outputset.cpp @@ -0,0 +1,153 @@ +// $Id: outputset.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*outputset.cpp + * + *output set assigns a flit which output to go to in a router + *used by the VC class + *the output assignment is done by the routing algorithms.. + * + */ + +#include <cassert> + +#include "booksim.hpp" +#include "outputset.hpp" + +void OutputSet::Clear( ) +{ + _outputs.clear( ); +} + +void OutputSet::Add( int output_port, int vc, int pri ) +{ + AddRange( output_port, vc, vc, pri ); +} + +void OutputSet::AddRange( int output_port, int vc_start, int vc_end, int pri ) +{ + + sSetElement s; + + s.vc_start = vc_start; + s.vc_end = vc_end; + s.pri = pri; + s.output_port = output_port; + _outputs.insert( s ); +} + +//legacy support, for performance, just use GetSet() +int OutputSet::NumVCs( int output_port ) const +{ + int total = 0; + set<sSetElement>::const_iterator i = _outputs.begin( ); + while(i!=_outputs.end( )){ + if(i->output_port == output_port){ + total += (i->vc_end - i->vc_start + 1); + } + i++; + } + return total; +} + +bool OutputSet::OutputEmpty( int output_port ) const +{ + set<sSetElement>::const_iterator i = _outputs.begin( ); + while(i!=_outputs.end( )){ + if(i->output_port == output_port){ + return false; + } + i++; + } + return true; +} + + +const set<OutputSet::sSetElement> & OutputSet::GetSet() const{ + return _outputs; +} + +//legacy support, for performance, just use GetSet() +int OutputSet::GetVC( int output_port, int vc_index, int *pri ) const +{ + + int range; + int remaining = vc_index; + int vc = -1; + + if ( pri ) { *pri = -1; } + + set<sSetElement>::const_iterator i = _outputs.begin( ); + while(i!=_outputs.end( )){ + if(i->output_port == output_port){ + range = i->vc_end - i->vc_start + 1; + if ( remaining >= range ) { + remaining -= range; + } else { + vc = i->vc_start + remaining; + if ( pri ) { + *pri = i->pri; + } + break; + } + } + i++; + } + return vc; +} + +//legacy support, for performance, just use GetSet() +bool OutputSet::GetPortVC( int *out_port, int *out_vc ) const +{ + + + bool single_output = false; + int used_outputs = 0; + + set<sSetElement>::const_iterator i = _outputs.begin( ); + if(i!=_outputs.end( )){ + used_outputs = i->output_port; + } + while(i!=_outputs.end( )){ + + if ( i->vc_start == i->vc_end ) { + *out_vc = i->vc_start; + *out_port = i->output_port; + single_output = true; + } else { + // multiple vc's selected + break; + } + if (used_outputs != i->output_port) { + // multiple outputs selected + single_output = false; + break; + } + i++; + } + return single_output; +} diff --git a/src/intersim2/outputset.hpp b/src/intersim2/outputset.hpp new file mode 100644 index 0000000..7f3e0fd --- /dev/null +++ b/src/intersim2/outputset.hpp @@ -0,0 +1,66 @@ +// $Id: outputset.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _OUTPUTSET_HPP_ +#define _OUTPUTSET_HPP_ + +#include <set> + +class OutputSet { + + +public: + struct sSetElement { + int vc_start; + int vc_end; + int pri; + int output_port; + }; + + void Clear( ); + void Add( int output_port, int vc, int pri = 0 ); + void AddRange( int output_port, int vc_start, int vc_end, int pri = 0 ); + + bool OutputEmpty( int output_port ) const; + int NumVCs( int output_port ) const; + + const set<sSetElement> & GetSet() const; + + int GetVC( int output_port, int vc_index, int *pri = 0 ) const; + bool GetPortVC( int *out_port, int *out_vc ) const; +private: + set<sSetElement> _outputs; +}; + +inline bool operator<(const OutputSet::sSetElement & se1, + const OutputSet::sSetElement & se2) { + return se1.pri > se2.pri; // higher priorities first! +} + +#endif + + diff --git a/src/intersim2/packet_reply_info.cpp b/src/intersim2/packet_reply_info.cpp new file mode 100644 index 0000000..7372882 --- /dev/null +++ b/src/intersim2/packet_reply_info.cpp @@ -0,0 +1,57 @@ +// $Id: packet_reply_info.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "packet_reply_info.hpp" + +stack<PacketReplyInfo*> PacketReplyInfo::_all; +stack<PacketReplyInfo*> PacketReplyInfo::_free; + +PacketReplyInfo * PacketReplyInfo::New() +{ + PacketReplyInfo * pr; + if(_free.empty()) { + pr = new PacketReplyInfo(); + _all.push(pr); + } else { + pr = _free.top(); + _free.pop(); + } + return pr; +} + +void PacketReplyInfo::Free() +{ + _free.push(this); +} + +void PacketReplyInfo::FreeAll() +{ + while(!_all.empty()) { + delete _all.top(); + _all.pop(); + } +} diff --git a/src/intersim2/packet_reply_info.hpp b/src/intersim2/packet_reply_info.hpp new file mode 100644 index 0000000..392dc85 --- /dev/null +++ b/src/intersim2/packet_reply_info.hpp @@ -0,0 +1,57 @@ +// $Id: packet_reply_info.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _PACKET_REPLY_INFO_HPP_ +#define _PACKET_REPLY_INFO_HPP_ + +#include <stack> + +#include "flit.hpp" + +//register the requests to a node +class PacketReplyInfo { + +public: + int source; + int time; + bool record; + Flit::FlitType type; + + static PacketReplyInfo* New(); + void Free(); + static void FreeAll(); + +private: + + static stack<PacketReplyInfo*> _all; + static stack<PacketReplyInfo*> _free; + + PacketReplyInfo() {} + ~PacketReplyInfo() {} +}; + +#endif diff --git a/src/intersim2/pipefifo.hpp b/src/intersim2/pipefifo.hpp new file mode 100644 index 0000000..03563b5 --- /dev/null +++ b/src/intersim2/pipefifo.hpp @@ -0,0 +1,97 @@ +// $Id: pipefifo.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _PIPEFIFO_HPP_ +#define _PIPEFIFO_HPP_ + +#include <vector> + +#include "module.hpp" + +template<class T> class PipelineFIFO : public Module { + int _lanes; + int _depth; + + int _pipe_len; + int _pipe_ptr; + + vector<vector<T*> > _data; + +public: + PipelineFIFO( Module *parent, const string& name, int lanes, int depth ); + ~PipelineFIFO( ); + + void Write( T* val, int lane = 0 ); + void WriteAll( T* val ); + + T* Read( int lane = 0 ); + + void Advance( ); +}; + +template<class T> PipelineFIFO<T>::PipelineFIFO( Module *parent, + const string& name, + int lanes, int depth ) : + Module( parent, name ), + _lanes( lanes ), _depth( depth ) +{ + _pipe_len = depth + 1; + _pipe_ptr = 0; + + _data.resize(_lanes); + for ( int l = 0; l < _lanes; ++l ) { + _data[l].resize(_pipe_len, 0); + } +} + +template<class T> PipelineFIFO<T>::~PipelineFIFO( ) +{ +} + +template<class T> void PipelineFIFO<T>::Write( T* val, int lane ) +{ + _data[lane][_pipe_ptr] = val; +} + +template<class T> void PipelineFIFO<T>::WriteAll( T* val ) +{ + for ( int l = 0; l < _lanes; ++l ) { + _data[l][_pipe_ptr] = val; + } +} + +template<class T> T* PipelineFIFO<T>::Read( int lane ) +{ + return _data[lane][_pipe_ptr]; +} + +template<class T> void PipelineFIFO<T>::Advance( ) +{ + _pipe_ptr = ( _pipe_ptr + 1 ) % _pipe_len; +} + +#endif diff --git a/src/intersim2/power/buffer_monitor.cpp b/src/intersim2/power/buffer_monitor.cpp new file mode 100644 index 0000000..aaf71f0 --- /dev/null +++ b/src/intersim2/power/buffer_monitor.cpp @@ -0,0 +1,71 @@ +// $Id: buffer_monitor.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "buffer_monitor.hpp" + +#include "flit.hpp" + +BufferMonitor::BufferMonitor( int inputs, int classes ) +: _cycles(0), _inputs(inputs), _classes(classes) { + _reads.resize(inputs * classes, 0) ; + _writes.resize(inputs * classes, 0) ; +} + +int BufferMonitor::index( int input, int cl ) const { + assert((input >= 0) && (input < _inputs)); + assert((cl >= 0) && (cl < _classes)); + return cl + _classes * input ; +} + +void BufferMonitor::cycle() { + _cycles++ ; +} + +void BufferMonitor::write( int input, Flit const * f ) { + _writes[ index(input, f->cl) ]++ ; +} + +void BufferMonitor::read( int input, Flit const * f ) { + _reads[ index(input, f->cl) ]++ ; +} + +void BufferMonitor::display(ostream & os) const { + for ( int i = 0 ; i < _inputs ; i++ ) { + os << "[ " << i << " ] " ; + for ( int c = 0 ; c < _classes ; c++ ) { + os << "Type=" << c + << ":(R#" << _reads[ index( i, c) ] << "," + << "W#" << _writes[ index( i, c) ] << ")" << " " ; + } + os << endl ; + } +} + +ostream & operator<<( ostream & os, BufferMonitor const & obj ) { + obj.display(os); + return os ; +} diff --git a/src/intersim2/power/buffer_monitor.hpp b/src/intersim2/power/buffer_monitor.hpp new file mode 100644 index 0000000..41b719f --- /dev/null +++ b/src/intersim2/power/buffer_monitor.hpp @@ -0,0 +1,68 @@ +// $Id: buffer_monitor.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _BUFFER_MONITOR_HPP_ +#define _BUFFER_MONITOR_HPP_ + +#include <vector> +#include <iostream> + +using namespace std; + +class Flit; + +class BufferMonitor { + int _cycles ; + int _inputs ; + int _classes ; + vector<int> _reads ; + vector<int> _writes ; + int index( int input, int cl ) const ; +public: + BufferMonitor( int inputs, int classes ) ; + void cycle() ; + void write( int input, Flit const * f ) ; + void read( int input, Flit const * f ) ; + inline const vector<int> & GetReads() const { + return _reads; + } + inline const vector<int> & GetWrites() const { + return _writes; + } + inline int NumInputs() const { + return _inputs; + } + inline int NumClasses() const { + return _classes; + } + void display(ostream & os) const; + +} ; + +ostream & operator<<( ostream & os, BufferMonitor const & obj ) ; + +#endif diff --git a/src/intersim2/power/power_module.cpp b/src/intersim2/power/power_module.cpp new file mode 100644 index 0000000..e319f4b --- /dev/null +++ b/src/intersim2/power/power_module.cpp @@ -0,0 +1,532 @@ +// $Id: power_module.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "power_module.hpp" +#include "booksim_config.hpp" +#include "buffer_monitor.hpp" +#include "switch_monitor.hpp" +#include "iq_router.hpp" + +Power_Module::Power_Module(Network * n , const Configuration &config) + : Module( 0, "power_module" ){ + + + string pfile = config.GetStr("tech_file"); + PowerConfig pconfig; + pconfig.ParseFile(pfile); + + net = n; + output_file_name = config.GetStr("power_output_file"); + classes = config.GetInt("classes"); + channel_width = (double)config.GetInt("channel_width"); + channel_sweep = (double)config.GetInt("channel_sweep"); + + numVC = (double)config.GetInt("num_vcs"); + depthVC = (double)config.GetInt("vc_buf_size"); + + //////////////////////////////////Constants///////////////////////////// + //wire length in (mm) + wire_length = pconfig.GetFloat("wire_length"); + //////////Metal Parameters//////////// + // Wire left/right coupling capacitance [ F/mm ] + Cw_cpl = pconfig.GetFloat("Cw_cpl"); + // Wire up/down groudn capacitance [ F/mm ] + Cw_gnd = pconfig.GetFloat("Cw_gnd"); + Cw = 2.0 * Cw_cpl + 2.0 * Cw_gnd ; + Rw = pconfig.GetFloat("Rw"); + // metal pitch [mm] + MetalPitch = pconfig.GetFloat("MetalPitch"); + + //////////Device Parameters//////////// + + LAMBDA = pconfig.GetFloat("LAMBDA") ; // [um/LAMBDA] + Cd = pconfig.GetFloat("Cd"); // [F/um] (for Delay) + Cg = pconfig.GetFloat("Cg"); // [F/um] (for Delay) + Cgdl = pconfig.GetFloat("Cgdl"); // [F/um] (for Delay) + + Cd_pwr = pconfig.GetFloat("Cd_pwr") ; // [F/um] (for Power) + Cg_pwr = pconfig.GetFloat("Cg_pwr") ; // [F/um] (for Power) + + IoffN = pconfig.GetFloat("IoffN"); // [A/um] + IoffP = pconfig.GetFloat("IoffP"); // [A/um] + // Leakage from bitlines, two-port cell [A] + IoffSRAM = pconfig.GetFloat("IoffSRAM"); + // [Ohm] ( D1=1um Inverter) + R = pconfig.GetFloat("R"); + // [F] ( D1=1um Inverter - for Power ) + Ci_delay = (1.0 + 2.0) * ( Cg + Cgdl ); + // [F] ( D1=1um Inverter - for Power ) + Co_delay = (1.0 + 2.0) * Cd ; + + + Ci = (1.0 + 2.0) * Cg_pwr ; + Co = (1.0 + 2.0) * Cd_pwr ; + + Vdd = pconfig.GetFloat("Vdd"); + FO4 = R * ( 3.0 * Cd + 12 * Cg + 12 * Cgdl); + tCLK = 20 * FO4; + fCLK = 1.0 / tCLK; + + H_INVD2=(double)pconfig.GetInt("H_INVD2"); + W_INVD2=(double)pconfig.GetInt("W_INVD2") ; + H_DFQD1=(double)pconfig.GetInt("H_DFQD1"); + W_DFQD1= (double)pconfig.GetInt("W_DFQD1"); + H_ND2D1= (double)pconfig.GetInt("H_ND2D1"); + W_ND2D1=(double)pconfig.GetInt("W_ND2D1"); + H_SRAM=(double)pconfig.GetInt("H_SRAM"); + W_SRAM=(double)pconfig.GetInt("W_SRAM"); + + ChannelPitch = 2.0 * MetalPitch ; + CrossbarPitch = 2.0 * MetalPitch ; +} + +Power_Module::~Power_Module(){ + + +} + + +////////////////////////////////////////////// +//Channels +////////////////////////////////////////////// + +void Power_Module::calcChannel(const FlitChannel* f){ + double channelLength = f->GetLatency()* wire_length; + wire const this_wire = wireOptimize(channelLength); + double const & K = this_wire.K; + double const & N = this_wire.N; + double const & M = this_wire.M; + //area + channelArea += areaChannel(K,N,M); + + //activity factor; + const vector<int> temp = f->GetActivity(); + vector<double> a(classes); + for(int i = 0; i< classes; i++){ + + a[i] = ((double)temp[i])/totalTime; + } + + //power calculation + double const bitPower = powerRepeatedWire(channelLength, K,M,N); + + channelClkPower += powerWireClk(M,channel_width); + for(int i = 0; i< classes; i++){ + channelWirePower += bitPower * a[i]*channel_width; + channelDFFPower += powerWireDFF(M, channel_width, a[i]); + } + channelLeakPower+= powerRepeatedWireLeak(K,M,N)*channel_width; +} + +wire const & Power_Module::wireOptimize(double L){ + map<double, wire>::iterator iter = wire_map.find(L); + if(iter == wire_map.end()){ + + double W = 64; + double bestMetric = 100000000 ; + double bestK = -1; + double bestM = -1; + double bestN = -1; + for (double K = 1.0 ; K < 10 ; K+=0.1 ) { + for (double N = 1.0 ; N < 40 ; N += 1.0 ) { + for (double M = 1.0 ; M < 40.0 ; M +=1.0 ) { + double l = 1.0 * L/( N * M) ; + + double k0 = R * (Co_delay + Ci_delay) ; + double k1 = R/K * Cw + K * Rw * Ci_delay ; + double k2 = 0.5 * Rw * Cw ; + double Tw = k0 + (k1 * l) + k2 * (l * l) ; + double alpha = 0.2 ; + double power = alpha * W * powerRepeatedWire( L, K, M, N) + powerWireDFF( M, W, alpha ) ; + double metric = M * M * M * M * power ; + if ( (N*Tw) < (0.8 * tCLK) ) { + if ( metric < bestMetric ) { + bestMetric = metric ; + bestK = K ; + bestM = M ; + bestN = N ; + } + } + } + } + } + cout<<"L = "<<L<<" K = "<<bestK<<" M = "<<bestM<<" N = "<<bestN<<endl; + + wire const temp = {L, bestK, bestM, bestN}; + iter = wire_map.insert(make_pair(L, temp)).first; + } + return iter->second; +} + +double Power_Module::powerRepeatedWire(double L, double K, double M, double N){ + + double segments = 1.0 * M * N ; + double Ca = K * (Ci + Co) + Cw * (L/segments) ; + double Pa = 0.5 * Ca * Vdd * Vdd * fCLK; + return Pa * M * N ; + +} + +double Power_Module::powerRepeatedWireLeak (double K, double M, double N){ + double Pl = K * 0.5 * ( IoffN + 2.0 * IoffP ) * Vdd ; + return Pl * M * N ; + +} + +double Power_Module:: powerWireClk (double M, double W){ + // number of clock wires running down one repeater bank + double columns = H_DFQD1 * MetalPitch / ChannelPitch ; + + // length of clock wire + double clockLength = W * ChannelPitch ; + double Cclk = (1 + 5.0/16.0 * (1+Co_delay/Ci_delay)) * (clockLength * Cw * columns +W * Ci_delay); + + return M * Cclk * (Vdd * Vdd) * fCLK ; + +} + +double Power_Module::powerWireDFF(double M, double W, double alpha){ + double Cdin = 2 * 0.8 * (Ci + Co) + 2 * ( 2.0/3.0 * 0.8 * Co ) ; + double Cclk = 2 * 0.8 * (Ci + Co) + 2 * ( 2.0/3.0 * 0.8 * Cg_pwr) ; + double Cint = (alpha * 0.5) * Cdin + alpha * Cclk ; + + return Cint * M * W * (Vdd*Vdd) * fCLK ; +} + + +/////////////////////////////////////////////////////////////// +//Memory +////////////////////////////////////////////////////////////// +void Power_Module::calcBuffer(const BufferMonitor *bm){ + double depth = numVC * depthVC ; + double Pleak = powerMemoryBitLeak( depth ) * channel_width ; + //area + + const vector<int> reads = bm->GetReads(); + const vector<int> writes = bm->GetWrites(); + for(int i = 0; i<bm->NumInputs(); i++){ + inputArea += areaInputModule( depth ); + inputLeakagePower += Pleak ; + for(int j = 0; j< classes; j++){ + double ar = ((double)reads[i* classes+j])/totalTime; + double aw = ((double)writes[i* classes+j])/totalTime; + if(ar>1 ||aw >1){ + cout<<"activity factor is greater than one, soemthing is stomping memory\n"; exit(-1); + } + double Pwl = powerWordLine( channel_width, depth) ; + double Prd = powerMemoryBitRead( depth ) * channel_width ; + double Pwr = powerMemoryBitWrite( depth ) * channel_width ; + inputReadPower += ar * ( Pwl + Prd ) ; + inputWritePower += aw * ( Pwl + Pwr ) ; + } + } +} + + +double Power_Module::powerWordLine(double memoryWidth, double memoryDepth){ + // wordline capacitance + double Ccell = 2 * ( 4.0 * LAMBDA ) * Cg_pwr + 6 * MetalPitch * Cw ; + double Cwl = memoryWidth * Ccell ; + + // wordline circuits + double Warray = 8 * MetalPitch + memoryDepth ; + double x = 1.0 + (5.0/16.0) * (1 + Co/Ci) ; + double Cpredecode = x * (Cw * Warray * Ci) ; + double Cdecode = x * Cwl ; + + // bitline circuits + double Harray = 6 * memoryWidth * MetalPitch ; + double y = (1 + 0.25) * (1 + Co/Ci) ; + double Cprecharge = y * ( Cw * Harray + 3 * channel_width * Ci ) ; + double Cwren = y * ( Cw * Harray + 2 * channel_width * Ci ) ; + + double Cbd = Cprecharge + Cwren ; + double Cwd = 2 * Cpredecode + Cdecode ; + + return ( Cbd + Cwd ) * Vdd * Vdd * fCLK ; + +} + +double Power_Module::powerMemoryBitRead(double memoryDepth){ + // bitline capacitance + double Ccell = 4.0 * LAMBDA * Cd_pwr + 8 * MetalPitch * Cw ; + double Cbl = memoryDepth * Ccell ; + double Vswing = Vdd ; + return ( Cbl ) * ( Vdd * Vswing ) * fCLK ; +} + +double Power_Module:: powerMemoryBitWrite(double memoryDepth){ + // bitline capacitance + double Ccell = 4.0 * LAMBDA * Cd_pwr + 8 * MetalPitch * Cw ; + double Cbl = memoryDepth * Ccell ; + + // internal capacitance + double Ccc = 2 * (Co + Ci) ; + + return (0.5 * Ccc * (Vdd*Vdd)) + ( Cbl ) * ( Vdd * Vdd ) * fCLK ; +} + +double Power_Module::powerMemoryBitLeak(double memoryDepth ){ + + return memoryDepth * IoffSRAM * Vdd ; +} + +/////////////////////////////////////////////////////////////// +//switch +////////////////////////////////////////////////////////////// + +void Power_Module::calcSwitch(const SwitchMonitor* sm){ + + switchArea += areaCrossbar(sm->NumInputs(), sm->NumOutputs()); + outputArea += areaOutputModule(sm->NumOutputs()); + switchPowerLeak += powerCrossbarLeak(channel_width, sm->NumInputs(), sm->NumOutputs()); + + const vector<int> activity = sm->GetActivity(); + vector<double> type_activity(classes); + + for(int i = 0; i<sm->NumOutputs(); i++){ + for(int k = 0; k<classes; k++){ + type_activity[k] = 0; + } + for(int j = 0; j<sm->NumInputs(); j++){ + for(int k = 0; k<classes; k++){ + double a = activity[k+classes*(i+sm->NumOutputs()*j)]; + a = a/totalTime; + if(a>1){ + cout<<"Switcht activity factor is greater than 1!!!\n";exit(-1); + } + double Px = powerCrossbar(channel_width, sm->NumInputs(),sm->NumOutputs(),j,i); + switchPower += a*channel_width*Px; + switchPowerCtrl += a *powerCrossbarCtrl(channel_width, sm->NumInputs(),sm->NumOutputs()); + type_activity[k]+=a; + } + } + outputPowerClk += powerWireClk( 1, channel_width ) ; + for(int k = 0; k<classes; k++){ + outputPower += type_activity[k] * powerWireDFF( 1, channel_width, 1.0 ) ; + outputCtrlPower += type_activity[k] * powerOutputCtrl(channel_width ) ; + } + } + +} + +double Power_Module::powerCrossbar(double width, double inputs, double outputs, double from, double to){ + // datapath traversal power + double Wxbar = width * outputs * CrossbarPitch ; + double Hxbar = width * inputs * CrossbarPitch ; + + // wires + double CwIn = Wxbar * Cw ; + double CwOut = Hxbar * Cw ; + + // cross-points + double Cxi = (1.0/16.0) * CwOut ; + double Cxo = 4.0 * Cxi * (Co_delay/Ci_delay) ; + + // drivers + double Cti = (1.0/16.0) * CwIn ; + double Cto = 4.0 * Cti * (Co_delay/Ci_delay) ; + + double CinputDriver = 5.0/16.0 * (1 + Co_delay/Ci_delay) * (0.5 * Cw * Wxbar + Cti) ; + + // total switched capacitance + + //this maybe missing +Cto + double Cin = CinputDriver + CwIn + Cti + (outputs * Cxi) ; + if ( to < outputs/2 ) { + Cin -= ( 0.5 * CwIn + outputs/2 * Cxi) ; + } + //this maybe missing +cti + double Cout = CwOut + Cto + (inputs * Cxo) ; + if ( from < inputs/2) { + Cout -= ( 0.5 * CwOut + (inputs/2 * Cxo)) ; + } + return 0.5 * (Cin + Cout) * (Vdd * Vdd * fCLK) ; +} + + +double Power_Module::powerCrossbarCtrl(double width, double inputs, double outputs){ + + // datapath traversal power + double Wxbar = width * outputs * CrossbarPitch ; + double Hxbar = width * inputs * CrossbarPitch ; + + // wires + double CwIn = Wxbar * Cw ; + + // drivers + double Cti = (5.0/16.0) * CwIn ; + + // need some estimate of how many control wires are required + double Cctrl = width * Cti + (Wxbar + Hxbar) * Cw ; + double Cdrive = (5.0/16.0) * (1 + Co_delay/Ci_delay) * Cctrl ; + + return (Cdrive + Cctrl) * (Vdd*Vdd) * fCLK ; + +} + +double Power_Module::powerCrossbarLeak (double width, double inputs, double outputs){ + // datapath traversal power + double Wxbar = width * outputs * CrossbarPitch ; + double Hxbar = width * inputs * CrossbarPitch ; + + // wires + double CwIn = Wxbar * Cw ; + double CwOut = Hxbar * Cw ; + // cross-points + double Cxi = (1.0/16.0) * CwOut ; + // drivers + double Cti = (1.0/16.0) * CwIn ; + + return 0.5 * (IoffN + 2 * IoffP)*width*(inputs*outputs*Cxi+inputs*Cti+outputs*Cti)/Ci; +} + +////////////////////////////////////////////////////////////////// +//output module +////////////////////////////////////////////////////////////////// +double Power_Module:: powerOutputCtrl(double width) { + + double Woutmod = channel_width * ChannelPitch ; + double Cen = Ci ; + + double Cenable = (1 + 5.0/16.0)*(1.0+Co/Ci)*(Woutmod* Cw + width* Cen) ; + + return Cenable * (Vdd*Vdd) * fCLK ; + +} + +////////////////////////////////////////////////////////////////// +//area +////////////////////////////////////////////////////////////////// + +double Power_Module:: areaChannel (double K, double N, double M){ + + double Adff = M * W_DFQD1 * H_DFQD1 ; + double Ainv = M * N * ( W_INVD2 + 3 * K) * H_INVD2 ; + + return channel_width * (Adff + Ainv) * MetalPitch * MetalPitch ; +} + +double Power_Module:: areaCrossbar(double Inputs, double Outputs) { + return (Inputs * channel_width * CrossbarPitch) * (Outputs * channel_width * CrossbarPitch) ; +} + +double Power_Module:: areaInputModule(double Words) { + double Asram = ( channel_width * H_SRAM ) * (Words * W_SRAM) ; + return Asram * (MetalPitch * MetalPitch) ; +} + +double Power_Module:: areaOutputModule(double Outputs) { + double Adff = Outputs * W_DFQD1 * H_DFQD1 ; + return channel_width * Adff * MetalPitch * MetalPitch ; +} + +void Power_Module::run(){ + totalTime = GetSimTime(); + channelWirePower=0; + channelClkPower=0; + channelDFFPower=0; + channelLeakPower=0; + inputReadPower=0; + inputWritePower=0; + inputLeakagePower=0; + switchPower=0; + switchPowerCtrl=0; + switchPowerLeak=0; + outputPower=0; + outputPowerClk=0; + outputCtrlPower=0; + channelArea=0; + switchArea=0; + inputArea=0; + outputArea=0; + maxInputPort = 0; + maxOutputPort = 0; + + vector<FlitChannel *> inject = net->GetInject(); + vector<FlitChannel *> eject = net->GetEject(); + vector<FlitChannel *> chan = net->GetChannels(); + + for(int i = 0; i<net->NumNodes(); i++){ + calcChannel(inject[i]); + } + + for(int i = 0; i<net->NumNodes(); i++){ + calcChannel(eject[i]); + } + + for(int i = 0; i<net->NumChannels();i++){ + calcChannel(chan[i]); + } + + vector<Router*> routers = net->GetRouters(); + for(size_t i = 0; i < routers.size(); i++){ + IQRouter* temp = dynamic_cast<IQRouter*>(routers[i]); + const BufferMonitor * bm = temp->GetBufferMonitor(); + calcBuffer(bm); + const SwitchMonitor * sm = temp->GetSwitchMonitor(); + calcSwitch(sm); + } + + double totalpower = channelWirePower+channelClkPower+channelDFFPower+channelLeakPower+ inputReadPower+inputWritePower+inputLeakagePower+ switchPower+switchPowerCtrl+switchPowerLeak+outputPower+outputPowerClk+outputCtrlPower; + double totalarea = channelArea+switchArea+inputArea+outputArea; + cout<< "-----------------------------------------\n" ; + cout<< "- OCN Power Summary\n" ; + cout<< "- Completion Time: "<<totalTime <<"\n" ; + cout<< "- Flit Widths: "<<channel_width<<"\n" ; + cout<< "- Channel Wire Power: "<<channelWirePower <<"\n" ; + cout<< "- Channel Clock Power: "<<channelClkPower <<"\n" ; + cout<< "- Channel Retiming Power: "<<channelDFFPower <<"\n" ; + cout<< "- Channel Leakage Power: "<<channelLeakPower <<"\n" ; + + cout<< "- Input Read Power: "<<inputReadPower <<"\n" ; + cout<< "- Input Write Power: "<<inputWritePower <<"\n" ; + cout<< "- Input Leakage Power: "<<inputLeakagePower <<"\n" ; + + cout<< "- Switch Power: "<<switchPower <<"\n" ; + cout<< "- Switch Control Power: "<<switchPowerCtrl <<"\n" ; + cout<< "- Switch Leakage Power: "<<switchPowerLeak <<"\n" ; + + cout<< "- Output DFF Power: "<<outputPower <<"\n" ; + cout<< "- Output Clk Power: "<<outputPowerClk <<"\n" ; + cout<< "- Output Control Power: "<<outputCtrlPower <<"\n" ; + cout<< "- Total Power: "<<totalpower <<"\n"; + cout<< "-----------------------------------------\n" ; + cout<< "\n" ; + cout<< "-----------------------------------------\n" ; + cout<< "- OCN Area Summary\n" ; + cout<< "- Channel Area: "<<channelArea<<"\n" ; + cout<< "- Switch Area: "<<switchArea<<"\n" ; + cout<< "- Input Area: "<<inputArea<<"\n" ; + cout<< "- Output Area: "<<outputArea<<"\n" ; + cout<< "- Total Area: "<<totalarea<<endl; + cout<< "-----------------------------------------\n" ; + + + + +} diff --git a/src/intersim2/power/power_module.hpp b/src/intersim2/power/power_module.hpp new file mode 100644 index 0000000..58be23c --- /dev/null +++ b/src/intersim2/power/power_module.hpp @@ -0,0 +1,186 @@ +// $Id: power_module.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _POWER_MODULE_HPP_ +#define _POWER_MODULE_HPP_ + +#include <map> + +#include "module.hpp" +#include "network.hpp" +#include "config_utils.hpp" +#include "flitchannel.hpp" +#include "switch_monitor.hpp" +#include "buffer_monitor.hpp" + +struct wire{ + double L; + double K; + double M; + double N; +}; + +class Power_Module : public Module { + +protected: + //network undersimulation + Network * net; + int classes; + //all channels are this width + double channel_width; + //resimulate all with channel_width decremented by channel_sweep until 0 + double channel_sweep; + //write result to a tabbed format to file + string output_file_name; + + //buffer depth + double depthVC; + //vcs + double numVC; + + //store the property of wires based on length + map<double, wire> wire_map; + + //////////////////////////////////Constants///////////////////////////// + //wire length in (mm) + double wire_length; + //////////Metal Parameters//////////// + // Wire left/right coupling capacitance [ F/mm ] + double Cw_cpl ; + // Wire up/down groudn capacitance [ F/mm ] + double Cw_gnd ; + double Cw ; + double Rw ; + // metal pitch [mm] + double MetalPitch ; + + + //////////Device Parameters//////////// + + double LAMBDA ; // [um/LAMBDA] + double Cd ; // [F/um] (for Delay) + double Cg ; // [F/um] (for Delay) + double Cgdl ; // [F/um] (for Delay) + + double Cd_pwr; // [F/um] (for Power) + double Cg_pwr ; // [F/um] (for Power) + + double IoffN ; // [A/um] + double IoffP ; // [A/um] + // Leakage from bitlines, two-port cell [A] + double IoffSRAM; + // [Ohm] ( D1=1um Inverter) + double R ; + // [F] ( D1=1um Inverter - for Power ) + double Ci_delay; + // [F] ( D1=1um Inverter - for Power ) + double Co_delay ; + + double Ci ; + double Co ; + double Vdd ; + double FO4 ; + double tCLK ; + double fCLK ; + + double H_INVD2; + double W_INVD2; + double H_DFQD1; + double W_DFQD1; + double H_ND2D1; + double W_ND2D1; + double H_SRAM; + double W_SRAM; + double ChannelPitch ; + double CrossbarPitch; + ////////////////////////////////End of Constants///////////////////////////// + + /////////////results/////////////////// + double totalTime; + double channelWirePower; + double channelClkPower; + double channelDFFPower; + double channelLeakPower; + double inputReadPower; + double inputWritePower; + double inputLeakagePower; + double switchPower; + double switchPowerCtrl; + double switchPowerLeak; + double outputPower; + double outputPowerClk; + double outputCtrlPower; + double channelArea; + double switchArea; + double inputArea; + double outputArea; + double maxInputPort; + double maxOutputPort; + + + //////////////////////// + + //channels + void calcChannel(const FlitChannel * f); + wire const & wireOptimize(double l); + double powerRepeatedWire(double L, double K, double M, double N); + double powerRepeatedWireLeak (double K, double M, double N); + double powerWireClk (double M, double W); + double powerWireDFF(double M, double W, double alpha); + + //memory + void calcBuffer(const BufferMonitor *bm); + double powerWordLine(double memoryWidth, double memoryDepth); + double powerMemoryBitRead(double memoryDepth); + double powerMemoryBitWrite(double memoryDepth); + double powerMemoryBitLeak(double memoryDepth ); + + //switch + void calcSwitch(const SwitchMonitor *sm); + double powerCrossbar(double width, double inputs, double outputs, double from, double to); + double powerCrossbarCtrl(double width, double inputs, double outputs); + double powerCrossbarLeak (double width, double inputs, double outputs); + + //output + double powerOutputCtrl(double width); + + //area + + double areaChannel (double K, double N, double M); + double areaCrossbar(double Inputs, double Outputs) ; + double areaInputModule(double Words) ; + double areaOutputModule(double Outputs); + +public: + Power_Module(Network * net, const Configuration &config); + ~Power_Module(); + + void run(); + + +}; +#endif diff --git a/src/intersim2/power/switch_monitor.cpp b/src/intersim2/power/switch_monitor.cpp new file mode 100644 index 0000000..f998cb1 --- /dev/null +++ b/src/intersim2/power/switch_monitor.cpp @@ -0,0 +1,67 @@ +// $Id: switch_monitor.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "switch_monitor.hpp" + +#include "flit.hpp" + +SwitchMonitor::SwitchMonitor( int inputs, int outputs, int classes ) +: _cycles(0), _inputs(inputs), _outputs(outputs), _classes(classes) { + _event.resize(inputs * outputs * classes, 0) ; +} + +int SwitchMonitor::index( int input, int output, int cl ) const { + assert((input >= 0) && (input < _inputs)); + assert((output >= 0) && (output < _outputs)); + assert((cl >= 0) && (cl < _classes)); + return cl + _classes * ( output + _outputs * input ) ; +} + +void SwitchMonitor::cycle() { + _cycles++ ; +} + +void SwitchMonitor::traversal( int input, int output, Flit const * f ) { + _event[ index( input, output, f->cl) ]++ ; +} + +void SwitchMonitor::display(ostream & os) const { + for ( int i = 0 ; i < _inputs ; i++ ) { + for ( int o = 0 ; o < _outputs ; o++) { + os << "[" << i << " -> " << o << "] " ; + for ( int c = 0 ; c < _classes ; c++ ) { + os << c << ":" << _event[index(i,o,c)] << " " ; + } + os << endl ; + } + } +} + +ostream & operator<<( ostream & os, SwitchMonitor const & obj ) { + obj.display(os); + return os ; +} diff --git a/src/intersim2/power/switch_monitor.hpp b/src/intersim2/power/switch_monitor.hpp new file mode 100644 index 0000000..dcc1276 --- /dev/null +++ b/src/intersim2/power/switch_monitor.hpp @@ -0,0 +1,66 @@ +// $Id: switch_monitor.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _SWITCH_MONITOR_HPP_ +#define _SWITCH_MONITOR_HPP_ + +#include <vector> +#include <iostream> + +using namespace std; + +class Flit; + +class SwitchMonitor { + int _cycles ; + int _inputs ; + int _outputs ; + int _classes ; + vector<int> _event ; + int index( int input, int output, int cl ) const ; +public: + SwitchMonitor( int inputs, int outputs, int classes ) ; + void cycle() ; + vector<int> const & GetActivity() const { + return _event; + } + inline int const & NumInputs() const { + return _inputs; + } + inline int const & NumOutputs() const { + return _outputs; + } + inline int const & NumClasses() const { + return _classes; + } + void traversal( int input, int output, Flit const * f ) ; + void display(ostream & os) const; +} ; + +ostream & operator<<( ostream & os, SwitchMonitor const & obj ) ; + +#endif diff --git a/src/intersim2/power/techfile.txt b/src/intersim2/power/techfile.txt new file mode 100755 index 0000000..c953713 --- /dev/null +++ b/src/intersim2/power/techfile.txt @@ -0,0 +1,26 @@ +// 2007 ITRS predictions for a 32nm high-performance library
+H_INVD2 = 8;//int
+W_INVD2 = 3;//int
+H_DFQD1 = 8;//int
+W_DFQD1 = 16;//int
+H_ND2D1 = 8;//int
+W_ND2D1 = 3;//int
+H_SRAM = 8;//int
+W_SRAM = 6;//int
+Vdd = 0.9;//float
+R = 606.321;//float
+IoffSRAM = 0.00000032;//float
+// 70 C
+IoffP = 0.00000102;//float
+IoffN = 0.00000102;//float
+Cg_pwr = 0.000000000000000534;//float
+Cd_pwr = 0.000000000000000267;//float
+Cgdl = 0.0000000000000001068;//float
+Cg = 0.000000000000000534;//float
+Cd = 0.000000000000000267;//float
+LAMBDA = 0.016;//float
+MetalPitch = 0.000080;//float
+Rw = 0.720044;//float
+Cw_gnd = 0.000000000000267339;//float
+Cw_cpl = 0.000000000000267339;//float
+wire_length = 2.0;//float
\ No newline at end of file diff --git a/src/intersim2/random_utils.hpp b/src/intersim2/random_utils.hpp new file mode 100644 index 0000000..1150b08 --- /dev/null +++ b/src/intersim2/random_utils.hpp @@ -0,0 +1,61 @@ +// $Id: random_utils.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _RANDOM_UTILS_HPP_ +#define _RANDOM_UTILS_HPP_ + + // interface to Knuth's RANARRAY RNG +void ran_start(long seed); +long ran_next( ); +void ranf_start(long seed); +double ranf_next( ); + +inline void RandomSeed( long seed ) { + ran_start( seed ); + ranf_start( seed ); +} + +inline unsigned long RandomIntLong( ) { + return ran_next( ); +} + +// Returns a random integer in the range [0,max] +inline int RandomInt( int max ) { + return ( ran_next( ) % (max+1) ); +} + +// Returns a random floating-point value in the rage [0,1] +inline double RandomFloat( ) { + return ranf_next( ); +} + +// Returns a random floating-point value in the rage [0,max] +inline double RandomFloat( double max ) { + return ( ranf_next( ) * max ); +} + +#endif diff --git a/src/intersim2/rng-double.c b/src/intersim2/rng-double.c new file mode 100644 index 0000000..27428d9 --- /dev/null +++ b/src/intersim2/rng-double.c @@ -0,0 +1,112 @@ +/* This program by D E Knuth is in the public domain and freely copyable. + * It is explained in Seminumerical Algorithms, 3rd edition, Section 3.6 + * (or in the errata to the 2nd edition --- see + * http://www-cs-faculty.stanford.edu/~knuth/taocp.html + * in the changes to Volume 2 on pages 171 and following). */ + +/* N.B. The MODIFICATIONS introduced in the 9th printing (2002) are + included here; there's no backwards compatibility with the original. */ + +/* This version also adopts Brendan McKay's suggestion to + accommodate naive users who forget to call ranf_start(seed). */ + +/* If you find any bugs, please report them immediately to + * (and you will be rewarded if the bug is genuine). Thanks! */ + +/************ see the book for explanations and caveats! *******************/ +/************ in particular, you need two's complement arithmetic **********/ + +#define KK 100 /* the long lag */ +#define LL 37 /* the short lag */ +#define mod_sum(x,y) (((x)+(y))-(int)((x)+(y))) /* (x+y) mod 1.0 */ + +double ran_u[KK]; /* the generator state */ + +#ifdef __STDC__ +void ranf_array(double aa[], int n) +#else +void ranf_array(aa,n) /* put n new random fractions in aa */ + double *aa; /* destination */ + int n; /* array length (must be at least KK) */ +#endif +{ + register int i,j; + for (j=0;j<KK;j++) aa[j]=ran_u[j]; + for (;j<n;j++) aa[j]=mod_sum(aa[j-KK],aa[j-LL]); + for (i=0;i<LL;i++,j++) ran_u[i]=mod_sum(aa[j-KK],aa[j-LL]); + for (;i<KK;i++,j++) ran_u[i]=mod_sum(aa[j-KK],ran_u[i-LL]); +} + +/* the following routines are adapted from exercise 3.6--15 */ +/* after calling ranf_start, get new randoms by, e.g., "x=ranf_arr_next()" */ + +#define QUALITY 1009 /* recommended quality level for high-res use */ +double ranf_arr_buf[QUALITY]; +double ranf_arr_dummy=-1.0, ranf_arr_started=-1.0; +double *ranf_arr_ptr=&ranf_arr_dummy; /* the next random fraction, or -1 */ + +#define TT 70 /* guaranteed separation between streams */ +#define is_odd(s) ((s)&1) + +#ifdef __STDC__ +void ranf_start(long seed) +#else +void ranf_start(seed) /* do this before using ranf_array */ + long seed; /* selector for different streams */ +#endif +{ + register int t,s,j; + double u[KK+KK-1]; + double ulp=(1.0/(1L<<30))/(1L<<22); /* 2 to the -52 */ + double ss=2.0*ulp*((seed&0x3fffffff)+2); + + for (j=0;j<KK;j++) { + u[j]=ss; /* bootstrap the buffer */ + ss+=ss; if (ss>=1.0) ss-=1.0-2*ulp; /* cyclic shift of 51 bits */ + } + u[1]+=ulp; /* make u[1] (and only u[1]) "odd" */ + for (s=seed&0x3fffffff,t=TT-1; t; ) { + for (j=KK-1;j>0;j--) + u[j+j]=u[j],u[j+j-1]=0.0; /* "square" */ + for (j=KK+KK-2;j>=KK;j--) { + u[j-(KK-LL)]=mod_sum(u[j-(KK-LL)],u[j]); + u[j-KK]=mod_sum(u[j-KK],u[j]); + } + if (is_odd(s)) { /* "multiply by z" */ + for (j=KK;j>0;j--) u[j]=u[j-1]; + u[0]=u[KK]; /* shift the buffer cyclically */ + u[LL]=mod_sum(u[LL],u[KK]); + } + if (s) s>>=1; else t--; + } + for (j=0;j<LL;j++) ran_u[j+KK-LL]=u[j]; + for (;j<KK;j++) ran_u[j-LL]=u[j]; + for (j=0;j<10;j++) ranf_array(u,KK+KK-1); /* warm things up */ + ranf_arr_ptr=&ranf_arr_started; +} + +#define ranf_arr_next() (*ranf_arr_ptr>=0? *ranf_arr_ptr++: ranf_arr_cycle()) +double ranf_arr_cycle() +{ + if (ranf_arr_ptr==&ranf_arr_dummy) + ranf_start(314159L); /* the user forgot to initialize */ + ranf_array(ranf_arr_buf,QUALITY); + ranf_arr_buf[KK]=-1; + ranf_arr_ptr=ranf_arr_buf+1; + return ranf_arr_buf[0]; +} + +#include <stdio.h> +int main() +{ + register int m; double a[2009]; /* a rudimentary test */ + ranf_start(310952); + for (m=0;m<2009;m++) ranf_array(a,1009); + printf("%.20f\n", ran_u[0]); /* 0.36410514377569680455 */ + /* beware of buggy printf routines that do not give full accuracy here! */ + ranf_start(310952); + for (m=0;m<1009;m++) ranf_array(a,2009); + printf("%.20f\n", ran_u[0]); /* 0.36410514377569680455 */ + return 0; +} diff --git a/src/intersim2/rng.c b/src/intersim2/rng.c new file mode 100644 index 0000000..c27740f --- /dev/null +++ b/src/intersim2/rng.c @@ -0,0 +1,108 @@ +/* This program by D E Knuth is in the public domain and freely copyable. + * It is explained in Seminumerical Algorithms, 3rd edition, Section 3.6 + * (or in the errata to the 2nd edition --- see + * http://www-cs-faculty.stanford.edu/~knuth/taocp.html + * in the changes to Volume 2 on pages 171 and following). */ + +/* N.B. The MODIFICATIONS introduced in the 9th printing (2002) are + included here; there's no backwards compatibility with the original. */ + +/* This version also adopts Brendan McKay's suggestion to + accommodate naive users who forget to call ran_start(seed). */ + +/* If you find any bugs, please report them immediately to + * (and you will be rewarded if the bug is genuine). Thanks! */ + +/************ see the book for explanations and caveats! *******************/ +/************ in particular, you need two's complement arithmetic **********/ + +#define KK 100 /* the long lag */ +#define LL 37 /* the short lag */ +#define MM (1L<<30) /* the modulus */ +#define mod_diff(x,y) (((x)-(y))&(MM-1)) /* subtraction mod MM */ + +long ran_x[KK]; /* the generator state */ + +#ifdef __STDC__ +void ran_array(long aa[],int n) +#else +void ran_array(aa,n) /* put n new random numbers in aa */ + long *aa; /* destination */ + int n; /* array length (must be at least KK) */ +#endif +{ + register int i,j; + for (j=0;j<KK;j++) aa[j]=ran_x[j]; + for (;j<n;j++) aa[j]=mod_diff(aa[j-KK],aa[j-LL]); + for (i=0;i<LL;i++,j++) ran_x[i]=mod_diff(aa[j-KK],aa[j-LL]); + for (;i<KK;i++,j++) ran_x[i]=mod_diff(aa[j-KK],ran_x[i-LL]); +} + +/* the following routines are from exercise 3.6--15 */ +/* after calling ran_start, get new randoms by, e.g., "x=ran_arr_next()" */ + +#define QUALITY 1009 /* recommended quality level for high-res use */ +long ran_arr_buf[QUALITY]; +long ran_arr_dummy=-1, ran_arr_started=-1; +long *ran_arr_ptr=&ran_arr_dummy; /* the next random number, or -1 */ + +#define TT 70 /* guaranteed separation between streams */ +#define is_odd(x) ((x)&1) /* units bit of x */ + +#ifdef __STDC__ +void ran_start(long seed) +#else +void ran_start(seed) /* do this before using ran_array */ + long seed; /* selector for different streams */ +#endif +{ + register int t,j; + long x[KK+KK-1]; /* the preparation buffer */ + register long ss=(seed+2)&(MM-2); + for (j=0;j<KK;j++) { + x[j]=ss; /* bootstrap the buffer */ + ss<<=1; if (ss>=MM) ss-=MM-2; /* cyclic shift 29 bits */ + } + x[1]++; /* make x[1] (and only x[1]) odd */ + for (ss=seed&(MM-1),t=TT-1; t; ) { + for (j=KK-1;j>0;j--) x[j+j]=x[j], x[j+j-1]=0; /* "square" */ + for (j=KK+KK-2;j>=KK;j--) + x[j-(KK-LL)]=mod_diff(x[j-(KK-LL)],x[j]), + x[j-KK]=mod_diff(x[j-KK],x[j]); + if (is_odd(ss)) { /* "multiply by z" */ + for (j=KK;j>0;j--) x[j]=x[j-1]; + x[0]=x[KK]; /* shift the buffer cyclically */ + x[LL]=mod_diff(x[LL],x[KK]); + } + if (ss) ss>>=1; else t--; + } + for (j=0;j<LL;j++) ran_x[j+KK-LL]=x[j]; + for (;j<KK;j++) ran_x[j-LL]=x[j]; + for (j=0;j<10;j++) ran_array(x,KK+KK-1); /* warm things up */ + ran_arr_ptr=&ran_arr_started; +} + +#define ran_arr_next() (*ran_arr_ptr>=0? *ran_arr_ptr++: ran_arr_cycle()) +long ran_arr_cycle() +{ + if (ran_arr_ptr==&ran_arr_dummy) + ran_start(314159L); /* the user forgot to initialize */ + ran_array(ran_arr_buf,QUALITY); + ran_arr_buf[KK]=-1; + ran_arr_ptr=ran_arr_buf+1; + return ran_arr_buf[0]; +} + +#include <stdio.h> +int main() +{ + register int m; long a[2009]; + ran_start(310952L); + for (m=0;m<=2009;m++) ran_array(a,1009); + printf("%ld\n", a[0]); /* 995235265 */ + ran_start(310952L); + for (m=0;m<=1009;m++) ran_array(a,2009); + printf("%ld\n", a[0]); /* 995235265 */ + return 0; +} diff --git a/src/intersim2/rng_double_wrapper.cpp b/src/intersim2/rng_double_wrapper.cpp new file mode 100644 index 0000000..ad4844c --- /dev/null +++ b/src/intersim2/rng_double_wrapper.cpp @@ -0,0 +1,34 @@ +// $Id: rng_double_wrapper.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#define main rng_double_main +#include "rng-double.c" + +double ranf_next( ) +{ + return ranf_arr_next( ); +} diff --git a/src/intersim2/rng_wrapper.cpp b/src/intersim2/rng_wrapper.cpp new file mode 100644 index 0000000..2e0cc2e --- /dev/null +++ b/src/intersim2/rng_wrapper.cpp @@ -0,0 +1,34 @@ +// $Id: rng_wrapper.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#define main rng_main +#include "rng.c" + +long ran_next( ) +{ + return ran_arr_next( ); +} diff --git a/src/intersim2/routefunc.cpp b/src/intersim2/routefunc.cpp new file mode 100644 index 0000000..567dcae --- /dev/null +++ b/src/intersim2/routefunc.cpp @@ -0,0 +1,1999 @@ +// $Id: routefunc.cpp 5507 2013-05-23 14:54:38Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*routefunc.cpp + * + *This is where most of the routing functions reside. Some of the topologies + *has their own "register routing functions" which must be called to access + *those routing functions. + * + *After writing a routing function, don't forget to register it. The reg + *format is rfname_topologyname. + * + */ + +#include <map> +#include <cstdlib> +#include <cassert> + +#include "booksim.hpp" +#include "routefunc.hpp" +#include "kncube.hpp" +#include "random_utils.hpp" +#include "misc_utils.hpp" +#include "fattree.hpp" +#include "tree4.hpp" +#include "qtree.hpp" +#include "cmesh.hpp" + + + +map<string, tRoutingFunction> gRoutingFunctionMap; + +/* Global information used by routing functions */ + +int gNumVCs; + +/* Add more functions here + * + */ + +// ============================================================ +// Balfour-Schultz +int gReadReqBeginVC, gReadReqEndVC; +int gWriteReqBeginVC, gWriteReqEndVC; +int gReadReplyBeginVC, gReadReplyEndVC; +int gWriteReplyBeginVC, gWriteReplyEndVC; + +// ============================================================ +// QTree: Nearest Common Ancestor +// === +void qtree_nca( const Router *r, const Flit *f, + int in_channel, OutputSet* outputs, bool inject) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int height = QTree::HeightFromID( r->GetID() ); + int pos = QTree::PosFromID( r->GetID() ); + + int dest = f->dest; + + for (int i = height+1; i < gN; i++) + dest /= gK; + if ( pos == dest / gK ) + // Route down to child + out_port = dest % gK ; + else + // Route up to parent + out_port = gK; + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +// ============================================================ +// Tree4: Nearest Common Ancestor w/ Adaptive Routing Up +// === +void tree4_anca( const Router *r, const Flit *f, + int in_channel, OutputSet* outputs, bool inject) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int range = 1; + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = f->dest; + + const int NPOS = 16; + + int rH = r->GetID( ) / NPOS; + int rP = r->GetID( ) % NPOS; + + if ( rH == 0 ) { + dest /= 16; + out_port = 2 * dest + RandomInt(1); + } else if ( rH == 1 ) { + dest /= 4; + if ( dest / 4 == rP / 2 ) + out_port = dest % 4; + else { + out_port = gK; + range = gK; + } + } else { + if ( dest/4 == rP ) + out_port = dest % 4; + else { + out_port = gK; + range = 2; + } + } + + // cout << "Router("<<rH<<","<<rP<<"): id= " << f->id << " dest= " << f->dest << " out_port = " + // << out_port << endl; + + } + + outputs->Clear( ); + + for (int i = 0; i < range; ++i) + outputs->AddRange( out_port + i, vcBegin, vcEnd ); +} + +// ============================================================ +// Tree4: Nearest Common Ancestor w/ Random Routing Up +// === +void tree4_nca( const Router *r, const Flit *f, + int in_channel, OutputSet* outputs, bool inject) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = f->dest; + + const int NPOS = 16; + + int rH = r->GetID( ) / NPOS; + int rP = r->GetID( ) % NPOS; + + if ( rH == 0 ) { + dest /= 16; + out_port = 2 * dest + RandomInt(1); + } else if ( rH == 1 ) { + dest /= 4; + if ( dest / 4 == rP / 2 ) + out_port = dest % 4; + else + out_port = gK + RandomInt(gK-1); + } else { + if ( dest/4 == rP ) + out_port = dest % 4; + else + out_port = gK + RandomInt(1); + } + + // cout << "Router("<<rH<<","<<rP<<"): id= " << f->id << " dest= " << f->dest << " out_port = " + // << out_port << endl; + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +// ============================================================ +// FATTREE: Nearest Common Ancestor w/ Random Routing Up +// === +void fattree_nca( const Router *r, const Flit *f, + int in_channel, OutputSet* outputs, bool inject) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int dest = f->dest; + int router_id = r->GetID(); //routers are numbered with smallest at the top level + int routers_per_level = powi(gK, gN-1); + int pos = router_id%routers_per_level; + int router_depth = router_id/ routers_per_level; //which level + int routers_per_neighborhood = powi(gK,gN-router_depth-1); + int router_neighborhood = pos/routers_per_neighborhood; //coverage of this tree + int router_coverage = powi(gK, gN-router_depth); //span of the tree from this router + + + //NCA reached going down + if(dest <(router_neighborhood+1)* router_coverage && + dest >=router_neighborhood* router_coverage){ + //down ports are numbered first + + //ejection + if(router_depth == gN-1){ + out_port = dest%gK; + } else { + //find the down port for the destination + int router_branch_coverage = powi(gK, gN-(router_depth+1)); + out_port = (dest-router_neighborhood* router_coverage)/router_branch_coverage; + } + } else { + //up ports are numbered last + assert(in_channel<gK);//came from a up channel + out_port = gK+RandomInt(gK-1); + } + } + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +// ============================================================ +// FATTREE: Nearest Common Ancestor w/ Adaptive Routing Up +// === +void fattree_anca( const Router *r, const Flit *f, + int in_channel, OutputSet* outputs, bool inject) +{ + + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + + int dest = f->dest; + int router_id = r->GetID(); //routers are numbered with smallest at the top level + int routers_per_level = powi(gK, gN-1); + int pos = router_id%routers_per_level; + int router_depth = router_id/ routers_per_level; //which level + int routers_per_neighborhood = powi(gK,gN-router_depth-1); + int router_neighborhood = pos/routers_per_neighborhood; //coverage of this tree + int router_coverage = powi(gK, gN-router_depth); //span of the tree from this router + + + //NCA reached going down + if(dest <(router_neighborhood+1)* router_coverage && + dest >=router_neighborhood* router_coverage){ + //down ports are numbered first + + //ejection + if(router_depth == gN-1){ + out_port = dest%gK; + } else { + //find the down port for the destination + int router_branch_coverage = powi(gK, gN-(router_depth+1)); + out_port = (dest-router_neighborhood* router_coverage)/router_branch_coverage; + } + } else { + //up ports are numbered last + assert(in_channel<gK);//came from a up channel + out_port = gK; + int random1 = RandomInt(gK-1); // Chose two ports out of the possible at random, compare loads, choose one. + int random2 = RandomInt(gK-1); + if (r->GetUsedCredit(out_port + random1) > r->GetUsedCredit(out_port + random2)){ + out_port = out_port + random2; + }else{ + out_port = out_port + random1; + } + } + } + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + + + + +// ============================================================ +// Mesh - adatpive XY,YX Routing +// pick xy or yx min routing adaptively at the source router +// === + +int dor_next_mesh( int cur, int dest, bool descending = false ); + +void adaptive_xy_yx_mesh( const Router *r, const Flit *f, + int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else if(r->GetID() == f->dest) { + + // at destination router, we don't need to separate VCs by dim order + out_port = 2*gN; + + } else { + + //each class must have at least 2 vcs assigned or else xy_yx will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + int out_port_xy = dor_next_mesh( r->GetID(), f->dest, false ); + int out_port_yx = dor_next_mesh( r->GetID(), f->dest, true ); + + // Route order (XY or YX) determined when packet is injected + // into the network, adaptively + bool x_then_y; + if(in_channel < 2*gN){ + x_then_y = (f->vc < (vcBegin + available_vcs)); + } else { + int credit_xy = r->GetUsedCredit(out_port_xy); + int credit_yx = r->GetUsedCredit(out_port_yx); + if(credit_xy > credit_yx) { + x_then_y = false; + } else if(credit_xy < credit_yx) { + x_then_y = true; + } else { + x_then_y = (RandomInt(1) > 0); + } + } + + if(x_then_y) { + out_port = out_port_xy; + vcEnd -= available_vcs; + } else { + out_port = out_port_yx; + vcBegin += available_vcs; + } + + } + + outputs->Clear(); + + outputs->AddRange( out_port , vcBegin, vcEnd ); + +} + +void xy_yx_mesh( const Router *r, const Flit *f, + int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else if(r->GetID() == f->dest) { + + // at destination router, we don't need to separate VCs by dim order + out_port = 2*gN; + + } else { + + //each class must have at least 2 vcs assigned or else xy_yx will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + // Route order (XY or YX) determined when packet is injected + // into the network + bool x_then_y = ((in_channel < 2*gN) ? + (f->vc < (vcBegin + available_vcs)) : + (RandomInt(1) > 0)); + + if(x_then_y) { + out_port = dor_next_mesh( r->GetID(), f->dest, false ); + vcEnd -= available_vcs; + } else { + out_port = dor_next_mesh( r->GetID(), f->dest, true ); + vcBegin += available_vcs; + } + + } + + outputs->Clear(); + + outputs->AddRange( out_port , vcBegin, vcEnd ); + +} + +// +// End Balfour-Schultz +//============================================================= + +//============================================================= + +int dor_next_mesh( int cur, int dest, bool descending ) +{ + if ( cur == dest ) { + return 2*gN; // Eject + } + + int dim_left; + + if(descending) { + for ( dim_left = ( gN - 1 ); dim_left > 0; --dim_left ) { + if ( ( cur * gK / gNodes ) != ( dest * gK / gNodes ) ) { break; } + cur = (cur * gK) % gNodes; dest = (dest * gK) % gNodes; + } + cur = (cur * gK) / gNodes; + dest = (dest * gK) / gNodes; + } else { + for ( dim_left = 0; dim_left < ( gN - 1 ); ++dim_left ) { + if ( ( cur % gK ) != ( dest % gK ) ) { break; } + cur /= gK; dest /= gK; + } + cur %= gK; + dest %= gK; + } + + if ( cur < dest ) { + return 2*dim_left; // Right + } else { + return 2*dim_left + 1; // Left + } +} + +//============================================================= + +void dor_next_torus( int cur, int dest, int in_port, + int *out_port, int *partition, + bool balance = false ) +{ + int dim_left; + int dir; + int dist2; + + for ( dim_left = 0; dim_left < gN; ++dim_left ) { + if ( ( cur % gK ) != ( dest % gK ) ) { break; } + cur /= gK; dest /= gK; + } + + if ( dim_left < gN ) { + + if ( (in_port/2) != dim_left ) { + // Turning into a new dimension + + cur %= gK; dest %= gK; + dist2 = gK - 2 * ( ( dest - cur + gK ) % gK ); + + if ( ( dist2 > 0 ) || + ( ( dist2 == 0 ) && ( RandomInt( 1 ) ) ) ) { + *out_port = 2*dim_left; // Right + dir = 0; + } else { + *out_port = 2*dim_left + 1; // Left + dir = 1; + } + + if ( partition ) { + if ( balance ) { + // Cray's "Partition" allocation + // Two datelines: one between k-1 and 0 which forces VC 1 + // another between ((k-1)/2) and ((k-1)/2 + 1) which + // forces VC 0 otherwise any VC can be used + + if ( ( ( dir == 0 ) && ( cur > dest ) ) || + ( ( dir == 1 ) && ( cur < dest ) ) ) { + *partition = 1; + } else if ( ( ( dir == 0 ) && ( cur <= (gK-1)/2 ) && ( dest > (gK-1)/2 ) ) || + ( ( dir == 1 ) && ( cur > (gK-1)/2 ) && ( dest <= (gK-1)/2 ) ) ) { + *partition = 0; + } else { + *partition = RandomInt( 1 ); // use either VC set + } + } else { + // Deterministic, fixed dateline between nodes k-1 and 0 + + if ( ( ( dir == 0 ) && ( cur > dest ) ) || + ( ( dir == 1 ) && ( dest < cur ) ) ) { + *partition = 1; + } else { + *partition = 0; + } + } + } + } else { + // Inverting the least significant bit keeps + // the packet moving in the same direction + *out_port = in_port ^ 0x1; + } + + } else { + *out_port = 2*gN; // Eject + } +} + +//============================================================= + +void dim_order_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int out_port = inject ? -1 : dor_next_mesh( r->GetID( ), f->dest ); + + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + if ( !inject && f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + outputs->Clear(); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void dim_order_ni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int out_port = inject ? -1 : dor_next_mesh( r->GetID( ), f->dest ); + + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + // at the destination router, we don't need to separate VCs by destination + if(inject || (r->GetID() != f->dest)) { + + int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes; + assert(vcs_per_dest > 0); + + vcBegin += f->dest * vcs_per_dest; + vcEnd = vcBegin + vcs_per_dest - 1; + + } + + if( !inject && f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void dim_order_pni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int out_port = inject ? -1 : dor_next_mesh( r->GetID(), f->dest ); + + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + if(inject || (r->GetID() != f->dest)) { + int next_coord = f->dest; + if(!inject) { + int out_dim = out_port / 2; + for(int d = 0; d < out_dim; ++d) { + next_coord /= gK; + } + } + next_coord %= gK; + assert(next_coord >= 0 && next_coord < gK); + int vcs_per_dest = (vcEnd - vcBegin + 1) / gK; + assert(vcs_per_dest > 0); + vcBegin += next_coord * vcs_per_dest; + vcEnd = vcBegin + vcs_per_dest - 1; + } + + if( !inject && f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +// Random intermediate in the minimal quadrant defined +// by the source and destination +int rand_min_intr_mesh( int src, int dest ) +{ + int dist; + + int intm = 0; + int offset = 1; + + for ( int n = 0; n < gN; ++n ) { + dist = ( dest % gK ) - ( src % gK ); + + if ( dist > 0 ) { + intm += offset * ( ( src % gK ) + RandomInt( dist ) ); + } else { + intm += offset * ( ( dest % gK ) + RandomInt( -dist ) ); + } + + offset *= gK; + dest /= gK; src /= gK; + } + + return intm; +} + +//============================================================= + +void romm_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + if ( in_channel == 2*gN ) { + f->ph = 0; // Phase 0 + f->intm = rand_min_intr_mesh( f->src, f->dest ); + } + + if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) { + f->ph = 1; // Go to phase 1 + } + + out_port = dor_next_mesh( r->GetID( ), (f->ph == 0) ? f->intm : f->dest ); + + // at the destination router, we don't need to separate VCs by phase + if(r->GetID() != f->dest) { + + //each class must have at least 2 vcs assigned or else valiant valiant will deadlock + int available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + if(f->ph == 0) { + vcEnd -= available_vcs; + } else { + assert(f->ph == 1); + vcBegin += available_vcs; + } + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void romm_ni_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + // at the destination router, we don't need to separate VCs by destination + if(inject || (r->GetID() != f->dest)) { + + int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes; + assert(vcs_per_dest > 0); + + vcBegin += f->dest * vcs_per_dest; + vcEnd = vcBegin + vcs_per_dest - 1; + + } + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + if ( in_channel == 2*gN ) { + f->ph = 0; // Phase 0 + f->intm = rand_min_intr_mesh( f->src, f->dest ); + } + + if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) { + f->ph = 1; // Go to phase 1 + } + + out_port = dor_next_mesh( r->GetID( ), (f->ph == 0) ? f->intm : f->dest ); + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void min_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + outputs->Clear( ); + + if(inject) { + // injection can use all VCs + outputs->AddRange(-1, vcBegin, vcEnd); + return; + } else if(r->GetID() == f->dest) { + // ejection can also use all VCs + outputs->AddRange(2*gN, vcBegin, vcEnd); + return; + } + + int in_vc; + + if ( in_channel == 2*gN ) { + in_vc = vcEnd; // ignore the injection VC + } else { + in_vc = f->vc; + } + + // DOR for the escape channel (VC 0), low priority + int out_port = dor_next_mesh( r->GetID( ), f->dest ); + outputs->AddRange( out_port, 0, vcBegin, vcBegin ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcBegin << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + if ( in_vc != vcBegin ) { // If not in the escape VC + // Minimal adaptive for all other channels + int cur = r->GetID( ); + int dest = f->dest; + + for ( int n = 0; n < gN; ++n ) { + if ( ( cur % gK ) != ( dest % gK ) ) { + // Add minimal direction in dimension 'n' + if ( ( cur % gK ) < ( dest % gK ) ) { // Right + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << (vcBegin+1) << "," + << vcEnd << "]" + << " at output port " << 2*n + << " with priority " << 1 + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + outputs->AddRange( 2*n, vcBegin+1, vcEnd, 1 ); + } else { // Left + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << (vcBegin+1) << "," + << vcEnd << "]" + << " at output port " << 2*n+1 + << " with priority " << 1 + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + outputs->AddRange( 2*n + 1, vcBegin+1, vcEnd, 1 ); + } + } + cur /= gK; + dest /= gK; + } + } +} + +//============================================================= + +void planar_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + outputs->Clear( ); + + if(inject) { + // injection can use all VCs + outputs->AddRange(-1, vcBegin, vcEnd); + return; + } + + int cur = r->GetID( ); + int dest = f->dest; + + if ( cur != dest ) { + + int in_vc = f->vc; + int vc_mult = (vcEnd - vcBegin + 1) / 3; + + // Find the first unmatched dimension -- except + // for when we're in the first dimension because + // of misrouting in the last adaptive plane. + // In this case, go to the last dimension instead. + + int n; + for ( n = 0; n < gN; ++n ) { + if ( ( ( cur % gK ) != ( dest % gK ) ) && + !( ( in_channel/2 == 0 ) && + ( n == 0 ) && + ( in_vc < vcBegin+2*vc_mult ) ) ) { + break; + } + + cur /= gK; + dest /= gK; + } + + assert( n < gN ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "PLANAR ADAPTIVE: flit " << f->id + << " in adaptive plane " << n << "." << endl; + } + + // We're in adaptive plane n + + // Can route productively in d_{i,2} + bool increase; + bool fault; + if ( ( cur % gK ) < ( dest % gK ) ) { // Increasing + increase = true; + if ( !r->IsFaultyOutput( 2*n ) ) { + outputs->AddRange( 2*n, vcBegin+2*vc_mult, vcEnd ); + fault = false; + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "PLANAR ADAPTIVE: increasing in dimension " << n + << "." << endl; + } + } else { + fault = true; + } + } else { // Decreasing + increase = false; + if ( !r->IsFaultyOutput( 2*n + 1 ) ) { + outputs->AddRange( 2*n + 1, vcBegin+2*vc_mult, vcEnd ); + fault = false; + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "PLANAR ADAPTIVE: decreasing in dimension " << n + << "." << endl; + } + } else { + fault = true; + } + } + + n = ( n + 1 ) % gN; + cur /= gK; + dest /= gK; + + if ( !increase ) { + vcBegin += vc_mult; + } + vcEnd = vcBegin + vc_mult - 1; + + int d1_min_c; + if ( ( cur % gK ) < ( dest % gK ) ) { // Increasing in d_{i+1} + d1_min_c = 2*n; + } else if ( ( cur % gK ) != ( dest % gK ) ) { // Decreasing in d_{i+1} + d1_min_c = 2*n + 1; + } else { + d1_min_c = -1; + } + + // do we want to 180? if so, the last + // route was a misroute in this dimension, + // if there is no fault in d_i, just ignore + // this dimension, otherwise continue to misroute + if ( d1_min_c == in_channel ) { + if ( fault ) { + d1_min_c = in_channel ^ 1; + } else { + d1_min_c = -1; + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "PLANAR ADAPTIVE: avoiding 180 in dimension " << n + << "." << endl; + } + } + + if ( d1_min_c != -1 ) { + if ( !r->IsFaultyOutput( d1_min_c ) ) { + outputs->AddRange( d1_min_c, vcBegin, vcEnd ); + } else if ( fault ) { + // major problem ... fault in d_i and d_{i+1} + r->Error( "There seem to be faults in d_i and d_{i+1}" ); + } + } else if ( fault ) { // need to misroute! + bool atedge; + if ( cur % gK == 0 ) { + d1_min_c = 2*n; + atedge = true; + } else if ( cur % gK == gK - 1 ) { + d1_min_c = 2*n + 1; + atedge = true; + } else { + d1_min_c = 2*n + RandomInt( 1 ); // random misroute + + if ( d1_min_c == in_channel ) { // don't 180 + d1_min_c = in_channel ^ 1; + } + atedge = false; + } + + if ( !r->IsFaultyOutput( d1_min_c ) ) { + outputs->AddRange( d1_min_c, vcBegin, vcEnd ); + } else if ( !atedge && !r->IsFaultyOutput( d1_min_c ^ 1 ) ) { + outputs->AddRange( d1_min_c ^ 1, vcBegin, vcEnd ); + } else { + // major problem ... fault in d_i and d_{i+1} + r->Error( "There seem to be faults in d_i and d_{i+1}" ); + } + } + } else { + outputs->AddRange( 2*gN, vcBegin, vcEnd ); + } +} + +//============================================================= +/* + FIXME: This is broken (note that f->dr is never actually modified). + Even if it were, this should really use f->ph instead of introducing a single- + use field. + +void limited_adapt_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + outputs->Clear( ); + + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + if ( inject ) { + outputs->AddRange( -1, vcBegin, vcEnd - 1 ); + f->dr = 0; // zero dimension reversals + return; + } + + int cur = r->GetID( ); + int dest = f->dest; + + if ( cur != dest ) { + if ( ( f->vc != vcEnd ) && + ( f->dr != vcEnd - 1 ) ) { + + for ( int n = 0; n < gN; ++n ) { + if ( ( cur % gK ) != ( dest % gK ) ) { + int min_port; + if ( ( cur % gK ) < ( dest % gK ) ) { + min_port = 2*n; // Right + } else { + min_port = 2*n + 1; // Left + } + + // Go in a productive direction with high priority + outputs->AddRange( min_port, vcBegin, vcEnd - 1, 2 ); + + // Go in the non-productive direction with low priority + outputs->AddRange( min_port ^ 0x1, vcBegin, vcEnd - 1, 1 ); + } else { + // Both directions are non-productive + outputs->AddRange( 2*n, vcBegin, vcEnd - 1, 1 ); + outputs->AddRange( 2*n+1, vcBegin, vcEnd - 1, 1 ); + } + + cur /= gK; + dest /= gK; + } + + } else { + outputs->AddRange( dor_next_mesh( cur, dest ), + vcEnd, vcEnd, 0 ); + } + + } else { // at destination + outputs->AddRange( 2*gN, vcBegin, vcEnd ); + } +} +*/ +//============================================================= + +void valiant_mesh( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + if ( in_channel == 2*gN ) { + f->ph = 0; // Phase 0 + f->intm = RandomInt( gNodes - 1 ); + } + + if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) { + f->ph = 1; // Go to phase 1 + } + + out_port = dor_next_mesh( r->GetID( ), (f->ph == 0) ? f->intm : f->dest ); + + // at the destination router, we don't need to separate VCs by phase + if(r->GetID() != f->dest) { + + //each class must have at least 2 vcs assigned or else valiant valiant will deadlock + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + if(f->ph == 0) { + vcEnd -= available_vcs; + } else { + assert(f->ph == 1); + vcBegin += available_vcs; + } + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void valiant_torus( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int phase; + if ( in_channel == 2*gN ) { + phase = 0; // Phase 0 + f->intm = RandomInt( gNodes - 1 ); + } else { + phase = f->ph / 2; + } + + if ( ( phase == 0 ) && ( r->GetID( ) == f->intm ) ) { + phase = 1; // Go to phase 1 + in_channel = 2*gN; // ensures correct vc selection at the beginning of phase 2 + } + + int ring_part; + dor_next_torus( r->GetID( ), (phase == 0) ? f->intm : f->dest, in_channel, + &out_port, &ring_part, false ); + + f->ph = 2 * phase + ring_part; + + // at the destination router, we don't need to separate VCs by phase, etc. + if(r->GetID() != f->dest) { + + int const ring_available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(ring_available_vcs > 0); + + if(ring_part == 0) { + vcEnd -= ring_available_vcs; + } else { + assert(ring_part == 1); + vcBegin += ring_available_vcs; + } + + int const ph_available_vcs = ring_available_vcs / 2; + assert(ph_available_vcs > 0); + + if(phase == 0) { + vcEnd -= ph_available_vcs; + } else { + assert(phase == 1); + vcBegin += ph_available_vcs; + } + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void valiant_ni_torus( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + // at the destination router, we don't need to separate VCs by destination + if(inject || (r->GetID() != f->dest)) { + + int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes; + assert(vcs_per_dest > 0); + + vcBegin += f->dest * vcs_per_dest; + vcEnd = vcBegin + vcs_per_dest - 1; + + } + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int phase; + if ( in_channel == 2*gN ) { + phase = 0; // Phase 0 + f->intm = RandomInt( gNodes - 1 ); + } else { + phase = f->ph / 2; + } + + if ( ( f->ph == 0 ) && ( r->GetID( ) == f->intm ) ) { + f->ph = 1; // Go to phase 1 + in_channel = 2*gN; // ensures correct vc selection at the beginning of phase 2 + } + + int ring_part; + dor_next_torus( r->GetID( ), (f->ph == 0) ? f->intm : f->dest, in_channel, + &out_port, &ring_part, false ); + + f->ph = 2 * phase + ring_part; + + // at the destination router, we don't need to separate VCs by phase, etc. + if(r->GetID() != f->dest) { + + int const ring_available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(ring_available_vcs > 0); + + if(ring_part == 0) { + vcEnd -= ring_available_vcs; + } else { + assert(ring_part == 1); + vcBegin += ring_available_vcs; + } + + int const ph_available_vcs = ring_available_vcs / 2; + assert(ph_available_vcs > 0); + + if(phase == 0) { + vcEnd -= ph_available_vcs; + } else { + assert(phase == 1); + vcBegin += ph_available_vcs; + } + } + + if (f->watch) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void dim_order_torus( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int cur = r->GetID( ); + int dest = f->dest; + + dor_next_torus( cur, dest, in_channel, + &out_port, &f->ph, false ); + + + // at the destination router, we don't need to separate VCs by ring partition + if(cur != dest) { + + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + if ( f->ph == 0 ) { + vcEnd -= available_vcs; + } else { + vcBegin += available_vcs; + } + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void dim_order_ni_torus( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int cur = r->GetID( ); + int dest = f->dest; + + dor_next_torus( cur, dest, in_channel, + &out_port, NULL, false ); + + // at the destination router, we don't need to separate VCs by destination + if(cur != dest) { + + int const vcs_per_dest = (vcEnd - vcBegin + 1) / gNodes; + assert(vcs_per_dest); + + vcBegin += f->dest * vcs_per_dest; + vcEnd = vcBegin + vcs_per_dest - 1; + + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void dim_order_bal_torus( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int cur = r->GetID( ); + int dest = f->dest; + + dor_next_torus( cur, dest, in_channel, + &out_port, &f->ph, true ); + + // at the destination router, we don't need to separate VCs by ring partition + if(cur != dest) { + + int const available_vcs = (vcEnd - vcBegin + 1) / 2; + assert(available_vcs > 0); + + if ( f->ph == 0 ) { + vcEnd -= available_vcs; + } else { + assert(f->ph == 1); + vcBegin += available_vcs; + } + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << r->FullName() << " | " + << "Adding VC range [" + << vcBegin << "," + << vcEnd << "]" + << " at output port " << out_port + << " for flit " << f->id + << " (input port " << in_channel + << ", destination " << f->dest << ")" + << "." << endl; + } + + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + +//============================================================= + +void min_adapt_torus( const Router *r, const Flit *f, int in_channel, OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + outputs->Clear( ); + + if(inject) { + // injection can use all VCs + outputs->AddRange(-1, vcBegin, vcEnd); + return; + } else if(r->GetID() == f->dest) { + // ejection can also use all VCs + outputs->AddRange(2*gN, vcBegin, vcEnd); + } + + int in_vc; + if ( in_channel == 2*gN ) { + in_vc = vcEnd; // ignore the injection VC + } else { + in_vc = f->vc; + } + + int cur = r->GetID( ); + int dest = f->dest; + + int out_port; + + if ( in_vc > ( vcBegin + 1 ) ) { // If not in the escape VCs + // Minimal adaptive for all other channels + + for ( int n = 0; n < gN; ++n ) { + if ( ( cur % gK ) != ( dest % gK ) ) { + int dist2 = gK - 2 * ( ( ( dest % gK ) - ( cur % gK ) + gK ) % gK ); + + if ( dist2 > 0 ) { /*) || + ( ( dist2 == 0 ) && ( RandomInt( 1 ) ) ) ) {*/ + outputs->AddRange( 2*n, vcBegin+3, vcBegin+3, 1 ); // Right + } else { + outputs->AddRange( 2*n + 1, vcBegin+3, vcBegin+3, 1 ); // Left + } + } + + cur /= gK; + dest /= gK; + } + + // DOR for the escape channel (VCs 0-1), low priority --- + // trick the algorithm with the in channel. want VC assignment + // as if we had injected at this node + dor_next_torus( r->GetID( ), f->dest, 2*gN, + &out_port, &f->ph, false ); + } else { + // DOR for the escape channel (VCs 0-1), low priority + dor_next_torus( cur, dest, in_channel, + &out_port, &f->ph, false ); + } + + if ( f->ph == 0 ) { + outputs->AddRange( out_port, vcBegin, vcBegin, 0 ); + } else { + outputs->AddRange( out_port, vcBegin+1, vcBegin+1, 0 ); + } +} + +//============================================================= + +void dest_tag_fly( const Router *r, const Flit *f, int in_channel, + OutputSet *outputs, bool inject ) +{ + int vcBegin = 0, vcEnd = gNumVCs-1; + if ( f->type == Flit::READ_REQUEST ) { + vcBegin = gReadReqBeginVC; + vcEnd = gReadReqEndVC; + } else if ( f->type == Flit::WRITE_REQUEST ) { + vcBegin = gWriteReqBeginVC; + vcEnd = gWriteReqEndVC; + } else if ( f->type == Flit::READ_REPLY ) { + vcBegin = gReadReplyBeginVC; + vcEnd = gReadReplyEndVC; + } else if ( f->type == Flit::WRITE_REPLY ) { + vcBegin = gWriteReplyBeginVC; + vcEnd = gWriteReplyEndVC; + } + assert(((f->vc >= vcBegin) && (f->vc <= vcEnd)) || (inject && (f->vc < 0))); + + int out_port; + + if(inject) { + + out_port = -1; + + } else { + + int stage = ( r->GetID( ) * gK ) / gNodes; + int dest = f->dest; + + while( stage < ( gN - 1 ) ) { + dest /= gK; + ++stage; + } + + out_port = dest % gK; + } + + outputs->Clear( ); + + outputs->AddRange( out_port, vcBegin, vcEnd ); +} + + + +//============================================================= + +void chaos_torus( const Router *r, const Flit *f, + int in_channel, OutputSet *outputs, bool inject ) +{ + outputs->Clear( ); + + if(inject) { + outputs->AddRange(-1, 0, 0); + return; + } + + int cur = r->GetID( ); + int dest = f->dest; + + if ( cur != dest ) { + for ( int n = 0; n < gN; ++n ) { + + if ( ( cur % gK ) != ( dest % gK ) ) { + int dist2 = gK - 2 * ( ( ( dest % gK ) - ( cur % gK ) + gK ) % gK ); + + if ( dist2 >= 0 ) { + outputs->AddRange( 2*n, 0, 0 ); // Right + } + + if ( dist2 <= 0 ) { + outputs->AddRange( 2*n + 1, 0, 0 ); // Left + } + } + + cur /= gK; + dest /= gK; + } + } else { + outputs->AddRange( 2*gN, 0, 0 ); + } +} + + +//============================================================= + +void chaos_mesh( const Router *r, const Flit *f, + int in_channel, OutputSet *outputs, bool inject ) +{ + outputs->Clear( ); + + if(inject) { + outputs->AddRange(-1, 0, 0); + return; + } + + int cur = r->GetID( ); + int dest = f->dest; + + if ( cur != dest ) { + for ( int n = 0; n < gN; ++n ) { + if ( ( cur % gK ) != ( dest % gK ) ) { + // Add minimal direction in dimension 'n' + if ( ( cur % gK ) < ( dest % gK ) ) { // Right + outputs->AddRange( 2*n, 0, 0 ); + } else { // Left + outputs->AddRange( 2*n + 1, 0, 0 ); + } + } + cur /= gK; + dest /= gK; + } + } else { + outputs->AddRange( 2*gN, 0, 0 ); + } +} + +//============================================================= + +void InitializeRoutingMap( const Configuration & config ) +{ + + gNumVCs = config.GetInt( "num_vcs" ); + + // + // traffic class partitions + // + gReadReqBeginVC = config.GetInt("read_request_begin_vc"); + if(gReadReqBeginVC < 0) { + gReadReqBeginVC = 0; + } + gReadReqEndVC = config.GetInt("read_request_end_vc"); + if(gReadReqEndVC < 0) { + gReadReqEndVC = gNumVCs / 2 - 1; + } + gWriteReqBeginVC = config.GetInt("write_request_begin_vc"); + if(gWriteReqBeginVC < 0) { + gWriteReqBeginVC = 0; + } + gWriteReqEndVC = config.GetInt("write_request_end_vc"); + if(gWriteReqEndVC < 0) { + gWriteReqEndVC = gNumVCs / 2 - 1; + } + gReadReplyBeginVC = config.GetInt("read_reply_begin_vc"); + if(gReadReplyBeginVC < 0) { + gReadReplyBeginVC = gNumVCs / 2; + } + gReadReplyEndVC = config.GetInt("read_reply_end_vc"); + if(gReadReplyEndVC < 0) { + gReadReplyEndVC = gNumVCs - 1; + } + gWriteReplyBeginVC = config.GetInt("write_reply_begin_vc"); + if(gWriteReplyBeginVC < 0) { + gWriteReplyBeginVC = gNumVCs / 2; + } + gWriteReplyEndVC = config.GetInt("write_reply_end_vc"); + if(gWriteReplyEndVC < 0) { + gWriteReplyEndVC = gNumVCs - 1; + } + + /* Register routing functions here */ + + // =================================================== + // Balfour-Schultz + gRoutingFunctionMap["nca_fattree"] = &fattree_nca; + gRoutingFunctionMap["anca_fattree"] = &fattree_anca; + gRoutingFunctionMap["nca_qtree"] = &qtree_nca; + gRoutingFunctionMap["nca_tree4"] = &tree4_nca; + gRoutingFunctionMap["anca_tree4"] = &tree4_anca; + gRoutingFunctionMap["dor_mesh"] = &dim_order_mesh; + gRoutingFunctionMap["xy_yx_mesh"] = &xy_yx_mesh; + gRoutingFunctionMap["adaptive_xy_yx_mesh"] = &adaptive_xy_yx_mesh; + // End Balfour-Schultz + // =================================================== + + gRoutingFunctionMap["dim_order_mesh"] = &dim_order_mesh; + gRoutingFunctionMap["dim_order_ni_mesh"] = &dim_order_ni_mesh; + gRoutingFunctionMap["dim_order_pni_mesh"] = &dim_order_pni_mesh; + gRoutingFunctionMap["dim_order_torus"] = &dim_order_torus; + gRoutingFunctionMap["dim_order_ni_torus"] = &dim_order_ni_torus; + gRoutingFunctionMap["dim_order_bal_torus"] = &dim_order_bal_torus; + + gRoutingFunctionMap["romm_mesh"] = &romm_mesh; + gRoutingFunctionMap["romm_ni_mesh"] = &romm_ni_mesh; + + gRoutingFunctionMap["min_adapt_mesh"] = &min_adapt_mesh; + gRoutingFunctionMap["min_adapt_torus"] = &min_adapt_torus; + + gRoutingFunctionMap["planar_adapt_mesh"] = &planar_adapt_mesh; + + // FIXME: This is broken. + // gRoutingFunctionMap["limited_adapt_mesh"] = &limited_adapt_mesh; + + gRoutingFunctionMap["valiant_mesh"] = &valiant_mesh; + gRoutingFunctionMap["valiant_torus"] = &valiant_torus; + gRoutingFunctionMap["valiant_ni_torus"] = &valiant_ni_torus; + + gRoutingFunctionMap["dest_tag_fly"] = &dest_tag_fly; + + gRoutingFunctionMap["chaos_mesh"] = &chaos_mesh; + gRoutingFunctionMap["chaos_torus"] = &chaos_torus; +} diff --git a/src/intersim2/routefunc.hpp b/src/intersim2/routefunc.hpp new file mode 100644 index 0000000..bf0c756 --- /dev/null +++ b/src/intersim2/routefunc.hpp @@ -0,0 +1,48 @@ +// $Id: routefunc.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _ROUTEFUNC_HPP_ +#define _ROUTEFUNC_HPP_ + +#include "flit.hpp" +#include "router.hpp" +#include "outputset.hpp" +#include "config_utils.hpp" + +typedef void (*tRoutingFunction)( const Router *, const Flit *, int in_channel, OutputSet *, bool ); + +void InitializeRoutingMap( const Configuration & config ); + +extern map<string, tRoutingFunction> gRoutingFunctionMap; + +extern int gNumVCs; +extern int gReadReqBeginVC, gReadReqEndVC; +extern int gWriteReqBeginVC, gWriteReqEndVC; +extern int gReadReplyBeginVC, gReadReplyEndVC; +extern int gWriteReplyBeginVC, gWriteReplyEndVC; + +#endif diff --git a/src/intersim2/routers/chaos_router.cpp b/src/intersim2/routers/chaos_router.cpp new file mode 100644 index 0000000..10c6277 --- /dev/null +++ b/src/intersim2/routers/chaos_router.cpp @@ -0,0 +1,673 @@ +// $Id: chaos_router.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "booksim.hpp" +#include <string> +#include <sstream> +#include <iostream> +#include <cstdlib> + +#include "chaos_router.hpp" +#include "random_utils.hpp" +#include "globals.hpp" + +ChaosRouter::ChaosRouter( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ) + : Router( config, + parent, name, + id, + inputs, outputs ) +{ + int i; + + if ( inputs != outputs ) { + Error( "Chaos router must have equal number of input and output ports" ); + } + + _buffer_size = config.GetInt( "vc_buf_size" ); + assert(_buffer_size >= config.GetInt( "const_flits_per_packet" )); + + _multi_queue_size = config.GetInt( "multi_queue_size" ); + + _cur_channel = 0; + _read_stall = 0; + + // Routing + + string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology"); + map<string, tRoutingFunction>::iterator rf_iter = gRoutingFunctionMap.find(rf); + if(rf_iter == gRoutingFunctionMap.end()) { + Error("Invalid routing function: " + rf); + } + _rf = rf_iter->second; + + _input_route.resize(_inputs); + + for ( i = 0; i < _inputs; ++i ) { + _input_route[i] = new OutputSet( ); + } + + _mq_route.resize(_multi_queue_size); + + for ( i = 0; i < _multi_queue_size; ++i ) { + _mq_route[i] = new OutputSet( ); + } + + // Alloc pipelines (to simulate processing/transmission delays) + + _crossbar_pipe = + new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs, + _crossbar_delay ); + + // Input and output queues + + _input_frame.resize(_inputs); + _output_frame.resize(_outputs); + _multi_queue.resize(_multi_queue_size); + + _credit_queue.resize(_inputs); + + _input_state.resize(_inputs, empty); + _input_output_match.resize(_inputs, -1); + _input_mq_match.resize(_inputs, -1); + + _output_matched.resize(_outputs, false); + _next_queue_cnt.resize(_outputs, 0); + + _multi_match.resize(_multi_queue_size, -1); + _mq_age.resize(_multi_queue_size); + _mq_matched.resize(_multi_queue_size, false); + _multi_state.resize(_multi_queue_size, empty); + + for ( i = 0; i < _multi_queue_size; ++i ) { + _multi_state[i] = empty; + _multi_match[i] = -1; + _mq_matched[i] = false; + } +} + +ChaosRouter::~ChaosRouter( ) +{ + int i; + + delete _crossbar_pipe; + + for ( i = 0; i < _inputs; ++i ) { + delete _input_route[i]; + } + + for ( i = 0; i < _multi_queue_size; ++i ) { + delete _mq_route[i]; + } +} + +void ChaosRouter::ReadInputs( ) +{ + Flit *f; + Credit *c; + + for ( int input = 0; input < _inputs; ++input ) { + f = _input_channels[input]->Receive(); + + if ( f ) { + _input_frame[input].push( f ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Flit arriving at " << FullName() + << " on channel " << input << endl + << *f; + } + + switch( _input_state[input] ) { + case empty: + if ( f->head ) { + if ( f->tail ) { + _input_state[input] = full; + } else { + _input_state[input] = filling; + } + _rf( this, f, input, _input_route[input], false ); + } else { + cout << *f; + Error( "Empty buffer received non-head flit!" ); + } + break; + + case filling: + if ( f->tail ) { + _input_state[input] = full; + } else if ( f->head ) { + Error( "Input buffer received another head before previous tail!" ); + } + break; + + case full: + Error( "Received flit while full!" ); + break; + + case leaving: + if ( f->head ) { + _input_state[input] = shared; + + if ( f->tail ) { + Error( "Received single-flit packet in leaving state!" ); + } + } else { + cout << *f; + Error( "Received non-head flit while packet leaving!" ); + } + break; + + case cut_through: + if ( f->tail ) { + _input_state[input] = leaving; + } + if ( f->head ) { + cout << *f; + Error( "Received head flit in cut through buffer!" ); + } + break; + + case shared: + if ( f->head ) { + Error( "Shared buffer received another head!" ); + } else if ( f->tail ) { + cout << "Input " << input << endl; + cout << *f; + Error( "Shared buffer received another tail!" ); + } + break; + } + } + } + + // Process incoming credits + + for ( int output = 0; output < _outputs; ++output ) { + c = _output_credits[output]->Receive(); + + if ( c ) { + _next_queue_cnt[output]--; + + if ( _next_queue_cnt[output] < 0 ) { + Error( "Next queue count fell below zero!" ); + } + + c->Free(); + } + } +} + +void ChaosRouter::_InternalStep( ) +{ + _NextInterestingChannel( ); + _OutputAdvance( ); + + _crossbar_pipe->Advance( ); +} + +void ChaosRouter::WriteOutputs( ) +{ + _SendFlits( ); + _SendCredits( ); +} + +bool ChaosRouter::_IsInjectionChan( int chan ) const +{ + return ( chan == _inputs - 1 ); +} + +bool ChaosRouter::_IsEjectionChan( int chan ) const +{ + return ( chan == _outputs - 1 ); +} + +bool ChaosRouter::_InputReady( int input ) const +{ + bool ready = false; + + if ( ( _input_state[input] == filling ) || + ( _input_state[input] == full ) ) { + ready = true; + } + + return ready; +} + +bool ChaosRouter::_OutputFull( int out ) const +{ + return ( _output_frame[out].size( ) >= (size_t)_buffer_size ); +} + +bool ChaosRouter::_OutputAvail( int out ) const +{ + return ( ( !_output_matched[out] ) && ( _output_frame[out].empty( ) ) ); + //&& ( _next_queue_cnt[out] == 0 ) ); + //return ( ( !_output_matched[out] ) && !_OutputFull( out ) ); +} + +bool ChaosRouter::_MultiQueueFull( int mq ) const +{ + return ( _multi_queue[mq].size( ) >= (size_t)_buffer_size ); +} + +int ChaosRouter::_InputForOutput( int output ) const +{ + // return an input that prefers this output + + int input; + int offset = RandomInt( _inputs - 1 ); + bool match = false; + + for ( int i = 0; ( i < _inputs ) && ( !match ); ++i ) { + input = ( i + offset ) % _inputs; + + if ( _InputReady( input ) && + ( ! _input_route[input]->OutputEmpty( output ) ) ) { + match = true; + } + } + + return match ? input : -1; +} + +int ChaosRouter::_MultiQueueForOutput( int output ) const +{ + // return oldest multi queue that prefers the output, + // or if none prefer and the multi queue is full, + // return a random entry + + int mq_oldest = -1; + int mq_age; + + int m, r; + + bool isfull = true; + + for ( int i = 0; i < _multi_queue_size; ++i ) { + if ( ( _multi_match[i] == -1 ) && + ( ( _multi_state[i] == full ) || + ( _multi_state[i] == filling ) ) ) { + + if ( ( !_mq_route[i]->OutputEmpty( output ) ) && + ( ( mq_oldest == -1 ) || ( _mq_age[i] > mq_age ) ) ) { + mq_oldest = i; + mq_age = _mq_age[i]; + } + } + + // deroute only if all queues contain head flits ... + + if ( ( _multi_state[i] != full ) && + ( _multi_state[i] != filling ) && + ( _multi_state[i] != shared ) ) { + isfull = false; + } + } + + // Don't deroute MQs to the ejection channel + if ( ( mq_oldest == -1 ) && isfull && + ( !_IsEjectionChan( output ) ) ) { + r = RandomInt( _multi_queue_size - 1 ); + + // Find first routable multi-queue + for ( int i = 0; i < _multi_queue_size; ++i ) { + m = ( i + r ) % _multi_queue_size; + if ( ( _multi_state[m] == filling ) || + ( _multi_state[m] == full ) ) { + mq_oldest = m; + //cout << "DEROUTING at " << FullName() << endl; + break; + } + } + + if ( mq_oldest == -1 ) { + cout << "write stall" << endl; + } + } + + return mq_oldest; +} + +int ChaosRouter::_FindAvailMultiQueue( ) const +{ + // return any empty multi queue slot + + int avail = -1; + + for ( int i = 0; i < _multi_queue_size; ++i ) { + if ( ( !_MultiQueueFull( i ) ) && + ( !_mq_matched[i] ) ) { + avail = i; + break; + } + } + + return avail; +} + +void ChaosRouter::_NextInterestingChannel( ) +{ + bool interesting; + + int mq_index; + int in_index; + int mq_avail; + + int c; + + interesting = false; + mq_index = -1; + in_index = -1; + + // A channel is interesting if + // + // ( output frame available and + // ( ( a multiqueue packet wants output channel ) or + // ( an input packet wants output channel ) or + // ( the multiqueue is full ) ) ) + // or + // ( the packet at the input channel is stalled ) + + for ( c = 0; ( c < _inputs ) && ( !interesting ); ++c ) { + if ( _OutputAvail( _cur_channel ) ) { + mq_index = _MultiQueueForOutput( _cur_channel ); + in_index = _InputForOutput( _cur_channel ); + + if ( ( mq_index != -1 ) || ( in_index != -1 ) ) { + interesting = true; + } + } + + if ( _input_state[_cur_channel] == full ) { + interesting = true; + } + + if ( !interesting ) { + _cur_channel = ( _cur_channel + 1 ) % _inputs; + } + } + + if ( interesting ) { + //cout << _cur_channel << " is interesting at " << FullName() << endl; + + if ( mq_index != -1 ) { + //cout << "Match for multi-queue " << mq_index << " at " << FullName() + // << ", output matched = " << _output_matched[_cur_channel] << endl; + + _output_matched[_cur_channel] = true; + _multi_match[mq_index] = _cur_channel; + } else if ( in_index != -1 ) { + _output_matched[_cur_channel] = true; + _input_output_match[in_index] = _cur_channel; + + //cout << "Match for input " << in_index << " at " << FullName() << endl; + + if ( _input_state[in_index] == full ) { + _input_state[in_index] = leaving; + } else if ( _input_state[in_index] == filling ) { + _input_state[in_index] = cut_through; + } else { + Error( "Tried to route input through crossbar that was not full or filling!" ); + } + } + + // Any non-injection channel that is routable is + // directed to the multi-queue + if ( ( ( _input_state[_cur_channel] == filling ) || + ( _input_state[_cur_channel] == full ) ) && + ( !_IsInjectionChan( _cur_channel ) ) ) { + ++_read_stall; + } else { + // go to next channel for the next cycle + _cur_channel = ( _cur_channel + 1 ) % _inputs; + _read_stall = 0; + } + } + + if ( _read_stall > 0 ) { + mq_avail = _FindAvailMultiQueue( ); + + if ( mq_avail != -1 ) { + if ( _input_state[_cur_channel] == full ) { + _input_state[_cur_channel] = leaving; + } else if ( _input_state[_cur_channel] == filling ) { + _input_state[_cur_channel] = cut_through; + } else { + cout << "Input " << _cur_channel << " state = " + << _input_state[_cur_channel] << endl; + Error( "Tried to route input throught multi-queue that was not full or filling!" ); + } + + _input_mq_match[_cur_channel] = mq_avail; + _mq_matched[mq_avail] = true; + + // go to next channel for the next cycle + _cur_channel = ( _cur_channel + 1 ) % _inputs; + _read_stall = 0; + } else { + ++_read_stall; + //cout << "stalling at input " << _cur_channel << " (count = " << _read_stall << ")" << endl; + } + } +} + +void ChaosRouter::_OutputAdvance( ) +{ + Flit *f, *f2; + Credit *c; + bool advanced; + int mq; + + _crossbar_pipe->WriteAll( 0 ); + + for ( int i = 0; i < _inputs; ++i ) { + if ( ( ( _input_output_match[i] != -1 ) || + ( _input_mq_match[i] != -1 ) ) && + ( !_input_frame[i].empty( ) ) ) { + + advanced = false; + f = _input_frame[i].front( ); + + /*if ( ! ) { + + } else { + cout << "Input = " << i + << ", input_output_match = " << _input_output_match[i] + << ", input_mq_match = " << _input_mq_match[i] << endl; + Error( "Input queue empty, but matched!" ); + }*/ + + if ( _input_output_match[i] != -1 ) { + if ( f->tail ) { + _output_matched[_input_output_match[i]] = false; + } + + _crossbar_pipe->Write( f, _input_output_match[i] ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Flit traversing crossbar from input queue " + << i << " at " + << FullName() << endl + << *f; + } + + advanced = true; + + } else if ( !_MultiQueueFull( _input_mq_match[i] ) ) { + + mq = _input_mq_match[i]; + + if ( f->head ) { + _rf( this, f, i, _mq_route[mq], false ); + _mq_age[mq] = 0; + + if ( _multi_state[mq] == empty ) { + _multi_state[mq] = filling; + } else if ( _multi_state[mq] == leaving ) { + _multi_state[mq] = shared; + } else { + Error( "Multi-queue received head while not empty or leaving!" ); + } + } + + if ( f->tail ) { + _mq_matched[mq] = false; + + if ( _multi_state[mq] == filling ) { + _multi_state[mq] = full; + } else if ( _multi_state[mq] == cut_through ) { + _multi_state[mq] = leaving; + } else { + Error( "Multi-queue received tail while not filling or cutting-through!" ); + } + } + + _multi_queue[mq].push( f ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Flit stored in multiqueue at " + << FullName() << endl + << "State = " << _multi_state[mq] << endl + << *f; + } + + advanced = true; + } + + if ( advanced ) { + _input_frame[i].pop( ); + + if ( f->tail ) { // last in packet, update state + if ( _input_state[i] == leaving ) { + _input_state[i] = empty; + } else if ( _input_state[i] == shared ) { + _input_state[i] = filling; + f2 = _input_frame[i].front( ); + // update routes + _rf( this, f2, i, _input_route[i], false ); + } + + _input_output_match[i] = -1; + _input_mq_match[i] = -1; + } + + c = Credit::New( ); + c->vc.insert(0); + _credit_queue[i].push( c ); + } + } + } + + for ( int m = 0; m < _multi_queue_size; ++m ) { + if ( _multi_match[m] != -1 ) { + if ( !_multi_queue[m].empty( ) ) { + f = _multi_queue[m].front( ); + _multi_queue[m].pop( ); + } else { + cout << "State = " << _multi_state[m] << endl; + Error( "Multi queue empty, but matched!" ); + } + + _crossbar_pipe->Write( f, _multi_match[m] ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Flit traversing crossbar from multiqueue slot " + << m << " at " + << FullName() << endl + << *f; + } + + if ( f->head ) { + if ( _multi_state[m] == filling ) { + _multi_state[m] = cut_through; + } else if ( _multi_state[m] == full ) { + _multi_state[m] = leaving; + } else { + Error( "Multi-queue sent head while not filling or full!" ); + } + } + + if ( f->tail ) { + _output_matched[_multi_match[m]] = false; + _multi_match[m] = -1; + + if ( _multi_state[m] == shared ) { + _multi_state[m] = filling; + } else if ( _multi_state[m] == leaving ) { + _multi_state[m] = empty; + } else { + cout << "State = " << _multi_state[m] << endl; + cout << *f; + Error( "Multi-queue sent tail while not leaving or shared!" ); + } + } + } + + _mq_age[m]++; + } +} + + +void ChaosRouter::_SendFlits( ) +{ + for ( int output = 0; output < _outputs; ++output ) { + Flit *f = _crossbar_pipe->Read( output ); + + if ( f ) { + _output_frame[output].push( f ); + f->hops++; + } + + if ( ( _next_queue_cnt[output] < _buffer_size ) && + ( !_output_frame[output].empty( ) ) ) { + _output_channels[output]->Send( _output_frame[output].front( ) ); + _output_frame[output].pop( ); + ++_next_queue_cnt[output]; + } + } +} + +void ChaosRouter::_SendCredits( ) +{ + for ( int input = 0; input < _inputs; ++input ) { + if ( !_credit_queue[input].empty( ) ) { + Credit *c = _credit_queue[input].front( ); + _credit_queue[input].pop( ); + _input_credits[input]->Send( c ); + } + } +} + +void ChaosRouter::Display( ostream & os ) const +{ +} diff --git a/src/intersim2/routers/chaos_router.hpp b/src/intersim2/routers/chaos_router.hpp new file mode 100644 index 0000000..df843ff --- /dev/null +++ b/src/intersim2/routers/chaos_router.hpp @@ -0,0 +1,132 @@ +// $Id: chaos_router.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _CHAOS_ROUTER_HPP_ +#define _CHAOS_ROUTER_HPP_ + +#include <string> +#include <queue> +#include <vector> + +#include "module.hpp" +#include "router.hpp" +#include "allocator.hpp" +#include "routefunc.hpp" +#include "outputset.hpp" +#include "buffer_state.hpp" +#include "pipefifo.hpp" +#include "vc.hpp" + +class ChaosRouter : public Router { + + tRoutingFunction _rf; + + vector<OutputSet*> _input_route; + vector<OutputSet*> _mq_route; + + enum eQState { + empty, // input avail + filling, // >**H ready to send + full, // T****H ready to send + leaving, // T***> input avail + cut_through, // >***> + shared // >**HT**> + }; + + PipelineFIFO<Flit> *_crossbar_pipe; + + int _multi_queue_size; + int _buffer_size; + + vector<queue<Flit *> > _input_frame; + vector<queue<Flit *> > _output_frame; + vector<queue<Flit *> > _multi_queue; + + vector<int> _next_queue_cnt; + + vector<queue<Credit *> > _credit_queue; + + vector<eQState> _input_state; + vector<eQState> _multi_state; + + vector<int> _input_output_match; + vector<int> _input_mq_match; + vector<int> _multi_match; + + vector<int> _mq_age; + + vector<bool> _output_matched; + vector<bool> _mq_matched; + + int _cur_channel; + int _read_stall; + + bool _IsInjectionChan( int chan ) const; + bool _IsEjectionChan( int chan ) const; + + bool _InputReady( int input ) const; + bool _OutputFull( int out ) const; + bool _OutputAvail( int out ) const; + bool _MultiQueueFull( int mq ) const; + + int _InputForOutput( int output ) const; + int _MultiQueueForOutput( int output ) const; + int _FindAvailMultiQueue( ) const; + + void _NextInterestingChannel( ); + void _OutputAdvance( ); + void _SendFlits( ); + void _SendCredits( ); + + virtual void _InternalStep( ); + +public: + ChaosRouter( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ); + + virtual ~ChaosRouter( ); + + virtual void ReadInputs( ); + virtual void WriteOutputs( ); + + virtual int GetUsedCredit(int out) const {return 0;} + virtual int GetBufferOccupancy(int i) const {return 0;} + +#ifdef TRACK_BUFFERS + virtual int GetUsedCreditForClass(int output, int cl) const {return 0;} + virtual int GetBufferOccupancyForClass(int input, int cl) const {return 0;} +#endif + + virtual vector<int> UsedCredits() const { return vector<int>(); } + virtual vector<int> FreeCredits() const { return vector<int>(); } + virtual vector<int> MaxCredits() const { return vector<int>(); } + + void Display( ostream & os = cout ) const; +}; + +#endif diff --git a/src/intersim2/routers/event_router.cpp b/src/intersim2/routers/event_router.cpp new file mode 100644 index 0000000..e3f9712 --- /dev/null +++ b/src/intersim2/routers/event_router.cpp @@ -0,0 +1,890 @@ +// $Id: event_router.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include <string> +#include <sstream> +#include <iostream> +#include <cstdlib> +#include <cassert> + +#include "event_router.hpp" +#include "stats.hpp" +#include "globals.hpp" + +EventRouter::EventRouter( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ) + : Router( config, + parent, name, + id, + inputs, outputs ) +{ + ostringstream module_name; + + _vcs = config.GetInt( "num_vcs" ); + + // Cut-through mode --- packets are not broken + // up and input buffers are assumed to be + // expressed in units of maximum size packets. + + _vct = config.GetInt( "vct" ); + + // Routing + + string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology"); + map<string, tRoutingFunction>::iterator rf_iter = gRoutingFunctionMap.find(rf); + if(rf_iter == gRoutingFunctionMap.end()) { + Error("Invalid routing function: " + rf); + } + _rf = rf_iter->second; + + // Alloc VC's + + _buf.resize(_inputs); + _active.resize(_inputs); + + for ( int i = 0; i < _inputs; ++i ) { + module_name << "buf_" << i; + _buf[i] = new Buffer( config, _outputs, this, module_name.str( ) ); + module_name.seekp( 0, ios::beg ); + _active[i].resize(_vcs, false); + } + + // Alloc next VCs' state + + _output_state.resize(_outputs); + + for ( int o = 0; o < _outputs; ++o ) { + module_name << "output" << o << "_vc_state"; + _output_state[o] = new EventNextVCState(config, this, module_name.str()); + module_name.seekp( 0, ios::beg ); + } + + // Alloc arbiters + + _arrival_arbiter.resize(_outputs); + + for ( int o = 0; o < _outputs; ++o ) { + module_name << "arrival_arb_output" << o; + _arrival_arbiter[o] = + new PriorityArbiter( config, this, module_name.str( ), _inputs ); + module_name.seekp( 0, ios::beg ); + } + + _transport_arbiter.resize(_inputs); + + for ( int i = 0; i < _inputs; ++i ) { + module_name << "transport_arb_input" << i; + _transport_arbiter[i] = + new PriorityArbiter( config, this, module_name.str( ), _outputs ); + module_name.seekp( 0, ios::beg ); + } + + // Alloc pipelines (to simulate processing/transmission delays) + + _crossbar_pipe = + new PipelineFIFO<Flit>( this, "crossbar_pipeline", _outputs, + _crossbar_delay ); + + _credit_pipe = + new PipelineFIFO<Credit>( this, "credit_pipeline", _inputs, + _credit_delay ); + + _arrival_pipe = + new PipelineFIFO<tArrivalEvent>( this, "arrival_pipeline", _inputs, + 0 /* FIX THIS EVENTUALLY */); + + // Queues + + _input_buffer.resize(_inputs); + _output_buffer.resize(_outputs); + + _in_cred_buffer.resize(_inputs); + _out_cred_buffer.resize(_outputs); + + _arrival_queue.resize(_inputs); + _transport_queue.resize(_outputs); + + // Misc. + + _transport_free.resize(_inputs, true); + _transport_match.resize(_inputs, -1); +} + +EventRouter::~EventRouter( ) +{ + for ( int i = 0; i < _inputs; ++i ) { + delete _buf[i]; + } + + for ( int o = 0; o < _outputs; ++o ) { + delete _output_state[o]; + } + + for ( int o = 0; o < _outputs; ++o ) { + delete _arrival_arbiter[o]; + } + + for ( int i = 0; i < _inputs; ++i ) { + delete _transport_arbiter[i]; + } + + delete _crossbar_pipe; + delete _credit_pipe; + delete _arrival_pipe; +} + +void EventRouter::ReadInputs( ) +{ + _ReceiveFlits( ); + _ReceiveCredits( ); +} + +void EventRouter::_InternalStep( ) +{ + // Receive incoming flits + _IncomingFlits( ); + + // The input pipe simulates routing delay + _arrival_pipe->Advance( ); + + // Clear output requests + for ( int output = 0; output < _outputs; ++output ) { + _arrival_arbiter[output]->Clear( ); + } + + // Check input arrival queues and generate + // requests for the outputs + for ( int input = 0; input < _inputs; ++input ) { + _ArrivalRequests( input ); + } + + // Arbitrate between requests at outputs + for ( int output = 0; output < _outputs; ++output ) { + _ArrivalArb( output ); + } + + for ( int input = 0; input < _inputs; ++input ) { + _transport_arbiter[input]->Clear( ); + } + + _crossbar_pipe->WriteAll( 0 ); + _credit_pipe->WriteAll( 0 ); + + // Generate transport events and their + // requests for the inputs + for ( int output = 0; output < _outputs; ++output ) { + _TransportRequests( output ); + } + + // Arbitrate between requests at inputs + for ( int input = 0; input < _inputs; ++input ) { + _TransportArb( input ); + } + + _crossbar_pipe->Advance( ); + _credit_pipe->Advance( ); + + _OutputQueuing( ); +} + +void EventRouter::WriteOutputs( ) +{ + _SendFlits( ); + _SendCredits( ); +} + +void EventRouter::_ReceiveFlits( ) +{ + Flit *f; + + for ( int input = 0; input < _inputs; ++input ) { + f = _input_channels[input]->Receive(); + + if ( f ) { + _input_buffer[input].push( f ); + } + } +} + +void EventRouter::_ReceiveCredits( ) +{ + Credit *c; + + for ( int output = 0; output < _outputs; ++output ) { + c = _output_credits[output]->Receive(); + + if ( c ) { + _out_cred_buffer[output].push( c ); + } + } +} + +void EventRouter::_ProcessWaiting( int output, int out_vc ) +{ + // out_vc just sent the transport event for out_vc, + // check if any events are queued on that vc. if so, + // generate another transport event and set the + // owner of the vc, otherwise set the vc to idle. + + int credits; + + tTransportEvent *tevt; + + EventNextVCState::tWaiting *w; + + if ( _output_state[output]->IsWaiting( out_vc ) ) { + + // State remains as busy, but the waiting VC takes over + w = _output_state[output]->PopWaiting( out_vc ); + + _output_state[output]->SetState( out_vc, EventNextVCState::busy ); + _output_state[output]->SetInput( out_vc, w->input ); + _output_state[output]->SetInputVC( out_vc, w->vc ); + + if ( w->watch ) { + cout << "Dequeuing waiting arrival event at " << FullName() + << " for flit " << w->id << endl; + } + + credits = _output_state[output]->GetCredits( out_vc ); + + // Try to queue a transmit event for a waiting packet + if ( credits > 0 ) { + tevt = new tTransportEvent; + tevt->src_vc = w->vc; + tevt->dst_vc = out_vc; + tevt->input = w->input; + tevt->watch = w->watch; // just to have something here + tevt->id = w->id; + + _transport_queue[output].push( tevt ); + + if ( tevt->watch ) { + cout << "Injecting transport event at " << FullName() + << " for flit " << tevt->id << endl; + } + + credits--; + _output_state[output]->SetCredits( out_vc, credits ); + _output_state[output]->SetPresence( out_vc, w->pres - 1 ); + + } else { + // No credits available, just store presence + _output_state[output]->SetPresence( out_vc, w->pres ); + } + + delete w; + + } else { + // Tail sent, none waiting => VC is idle + _output_state[output]->SetState( out_vc, EventNextVCState::idle ); + } +} + +void EventRouter::_IncomingFlits( ) +{ + Flit *f; + Buffer *cur_buf; + + tArrivalEvent *aevt; + + _arrival_pipe->WriteAll( 0 ); + + for ( int input = 0; input < _inputs; ++input ) { + if ( !_input_buffer[input].empty( ) ) { + f = _input_buffer[input].front( ); + _input_buffer[input].pop( ); + + cur_buf = _buf[input]; + int vc = f->vc; + + cur_buf->AddFlit( vc, f ); + + // Head flit arriving at idle VC + if ( !_active[input][vc] ) { + + if ( !f->head ) { + cout << "Non-head flit:" << endl; + cout << *f; + Error( "Received non-head flit at idle VC" ); + } + + const OutputSet *route_set; + int out_vc, out_port; + + cur_buf->Route( vc, _rf, this, f, input ); + route_set = cur_buf->GetRouteSet( vc ); + + if ( !route_set->GetPortVC( &out_port, &out_vc ) ) { + Error( "The event-driven router requires routing functions with a single (port,vc) output" ); + } + + cur_buf->SetOutput( vc, out_port, out_vc ); + _active[input][vc] = true; + } else { + if ( f->head ) { + cout << *f; + Error( "Received head flit at non-idle VC." ); + } + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Received flit at " << FullName() << ". Output port = " + << cur_buf->GetOutputPort( vc ) << ", output VC = " + << cur_buf->GetOutputVC( vc ) << endl + << *f; + } + + // In cut-through mode, only head flits generate arrivals, + // otherwise all flits generate + + if ( ( !_vct ) || ( _vct && f->head ) ) { + // Add the arrival event to a delay pipeline to + // account for routing/decoding time + + aevt = new tArrivalEvent; + + aevt->input = input; + aevt->output = cur_buf->GetOutputPort( vc ); + aevt->src_vc = f->vc; + aevt->dst_vc = cur_buf->GetOutputVC( vc ); + aevt->head = f->head; + aevt->tail = f->tail; + + //if ( f->head && f->tail ) { + // Error( "Head/tail packets not supported." ); + //} + + aevt->watch = f->watch; + aevt->id = f->id; + + _arrival_pipe->Write( aevt, input ); + + if ( aevt->watch ) { + cout << "Injected arrival event at " << FullName() + << " for flit " << aevt->id << endl; + } + } + } + } +} + +void EventRouter::_ArrivalRequests( int input ) +{ + tArrivalEvent *aevt; + + aevt = _arrival_pipe->Read( input ); + if ( aevt ) { + _arrival_queue[input].push( aevt ); + } + + if ( !_arrival_queue[input].empty( ) ) { + aevt = _arrival_queue[input].front( ); + _arrival_arbiter[aevt->output]->AddRequest( input ); + } +} + +void EventRouter::_SendTransport( int input, int output, tArrivalEvent *aevt ) +{ + // Try to send a transport event + + tTransportEvent *tevt; + + int credits; + int pres; + + credits = _output_state[output]->GetCredits( aevt->dst_vc ); + + if ( credits > 0 ) { + // Take a credit and queue a transport event + credits--; + _output_state[output]->SetCredits( aevt->dst_vc, credits ); + + tevt = new tTransportEvent; + tevt->src_vc = aevt->src_vc; + tevt->dst_vc = aevt->dst_vc; + tevt->input = input; + tevt->watch = aevt->watch; + tevt->id = aevt->id; + + _transport_queue[output].push( tevt ); + + if ( tevt->watch ) { + cout << "Injecting transport event at " << FullName() + << " for flit " << tevt->id << endl; + } + } else { + if ( aevt->watch ) { + cout << "No credits available at " << FullName() + << " for flit " << aevt->id << " storing presence." << endl; + } + + // No credits available, just store presence + pres = _output_state[output]->GetPresence( aevt->dst_vc ); + _output_state[output]->SetPresence( aevt->dst_vc, pres + 1 ); + } +} + +void EventRouter::_ArrivalArb( int output ) +{ + tArrivalEvent *aevt; + tTransportEvent *tevt; + Credit *c; + + EventNextVCState::tWaiting *w; + + int input; + int credits; + int pres; + + // Incoming credits can produce or enable + // transport events --- process them first + + if ( !_out_cred_buffer[output].empty( ) ) { + c = _out_cred_buffer[output].front( ); + _out_cred_buffer[output].pop( ); + + assert( c->vc.size() == 1 ); + int vc = *c->vc.begin(); + + EventNextVCState::eNextVCState state = + _output_state[output]->GetState( vc ); + + credits = _output_state[output]->GetCredits( vc ); + pres = _output_state[output]->GetPresence( vc ); + + if ( _vct ) { + // In cut-through mode, only head credits indicate a change in + // channel state. + + if ( c->head ) { + credits++; + _output_state[output]->SetCredits( vc, credits ); + _ProcessWaiting( output, vc ); + } + } else { + credits++; + _output_state[output]->SetCredits( vc, credits ); + + if ( c->tail ) { // tail flit -- recycle VC + if ( state != EventNextVCState::busy ) { + Error( "Received tail credit at non-busy output VC" ); + } + + _ProcessWaiting( output, vc ); + } else if ( ( state == EventNextVCState::busy ) && ( pres > 0 ) ) { + // Flit is present => generate transport event + + tevt = new tTransportEvent; + tevt->input = _output_state[output]->GetInput( vc ); + tevt->src_vc = _output_state[output]->GetInputVC( vc ); + tevt->dst_vc = vc; + tevt->watch = false; + tevt->id = -1; + + _transport_queue[output].push( tevt ); + + pres--; + credits--; + _output_state[output]->SetPresence( vc, pres ); + _output_state[output]->SetCredits( vc, credits ); + } + } + + c->Free(); + } + + // Now process arrival events + + _arrival_arbiter[output]->Arbitrate( ); + input = _arrival_arbiter[output]->Match( ); + + if ( input != -1 ) { + // Winning arrival event gets access to output + + aevt = _arrival_queue[input].front( ); + _arrival_queue[input].pop( ); + + if ( aevt->watch ) { + cout << "Processing arrival event at " << FullName() + << " for flit " << aevt->id << endl; + } + + EventNextVCState::eNextVCState state = + _output_state[output]->GetState( aevt->dst_vc ); + + if ( aevt->head ) { // Head flits + if ( state == EventNextVCState::idle ) { + // Allocate the output VC and queue a transport event + _output_state[output]->SetState( aevt->dst_vc, EventNextVCState::busy ); + _output_state[output]->SetInput( aevt->dst_vc, input ); + _output_state[output]->SetInputVC( aevt->dst_vc, aevt->src_vc ); + + _SendTransport( input, output, aevt ); + } else { + // VC busy => queue a waiting event + + w = new EventNextVCState::tWaiting; + + w->input = input; + w->vc = aevt->src_vc; + w->id = aevt->id; + w->watch = aevt->watch; + w->pres = 1; + + _output_state[output]->PushWaiting( aevt->dst_vc, w ); + } + } else { + if ( _vct ) { + Error( "Received arrival event for non-head flit in cut-through mode" ); + } + + if ( state != EventNextVCState::busy ) { + cout << "flit id = " << aevt->id << endl; + Error( "Received a body flit at a non-busy output VC" ); + } + + if ( ( !_output_state[output]->IsInputWaiting( aevt->dst_vc, input, aevt->src_vc ) ) && + ( input == _output_state[output]->GetInput( aevt->dst_vc ) ) && + ( aevt->src_vc == _output_state[output]->GetInputVC( aevt->dst_vc ) ) ) { + // Body flit part of the current active VC => queue transport event + // (the weird IsInputWaiting call handles a body flit waiting in addition + // to a head flit) + + _SendTransport( input, output, aevt ); + } else { + + // VC busy with a differnet transaction => update waiting event + _output_state[output]->IncrWaiting( aevt->dst_vc, input, aevt->src_vc ); + } + } + + delete aevt; + } +} + +void EventRouter::_TransportRequests( int output ) +{ + tTransportEvent *tevt; + + if ( !_transport_queue[output].empty( ) ) { + tevt = _transport_queue[output].front( ); + _transport_arbiter[tevt->input]->AddRequest( output ); + } +} + +void EventRouter::_TransportArb( int input ) +{ + tTransportEvent *tevt; + + int output; + Buffer *cur_buf; + Flit *f; + Credit *c; + + if ( _transport_free[input] ) { + _transport_arbiter[input]->Arbitrate( ); + output = _transport_arbiter[input]->Match( ); + } else { + output = _transport_match[input]; + } + + if ( output != -1 ) { + // This completes the match from input to output => + // one flit can be transferred + + tevt = _transport_queue[output].front( ); + + if ( tevt->watch ) { + cout << "Processing transport event at " << FullName() + << " for flit " << tevt->id << endl; + } + + cur_buf = _buf[input]; + int vc = tevt->src_vc; + + // Some sanity checking first + + if ( !_active[input][vc] ) { + Error( "Non-active VC received grant." ); + } + + if ( cur_buf->Empty( vc ) ) { + return; //Error( "Empty VC received grant." ); + } + + if ( tevt->dst_vc != cur_buf->GetOutputVC( vc ) ) { + Error( "Transport event's VC does not match input's destination VC." ); + } + + f = cur_buf->RemoveFlit( vc ); + + if ( _vct ) { + if ( f->tail ) { + _transport_free[input] = true; + _transport_match[input] = -1; + + _transport_queue[output].pop( ); + delete tevt; + + _active[input][vc] = false; + } else { + _transport_free[input] = false; + _transport_match[input] = output; + } + } else { + _transport_free[input] = true; + _transport_match[input] = -1; + + _transport_queue[output].pop( ); + delete tevt; + + if ( f->tail ) { + _active[input][vc] = false; + } + } + + c = Credit::New( ); + c->vc.insert(f->vc); + c->head = f->head; + c->tail = f->tail; + c->id = f->id; + _credit_pipe->Write( c, input ); + + if ( f->watch && c->tail ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << FullName() << " sending tail credit back for flit " << f->id << endl; + } + + // Update and forward the flit to the crossbar + + f->hops++; + f->vc = cur_buf->GetOutputVC( vc ); + _crossbar_pipe->Write( f, output ); + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Forwarding flit through crossbar at " << FullName() << ":" << endl + << *f; + } + } +} + +void EventRouter::_OutputQueuing( ) +{ + Flit *f; + Credit *c; + + for ( int output = 0; output < _outputs; ++output ) { + f = _crossbar_pipe->Read( output ); + + if ( f ) { + _output_buffer[output].push( f ); + } + } + + for ( int input = 0; input < _inputs; ++input ) { + c = _credit_pipe->Read( input ); + + if ( c ) { + _in_cred_buffer[input].push( c ); + } + } +} + +void EventRouter::_SendFlits( ) +{ + for ( int output = 0; output < _outputs; ++output ) { + if ( !_output_buffer[output].empty( ) ) { + Flit *f = _output_buffer[output].front( ); + _output_buffer[output].pop( ); + _output_channels[output]->Send( f ); + } + } +} + +void EventRouter::_SendCredits( ) +{ + for ( int input = 0; input < _inputs; ++input ) { + if ( !_in_cred_buffer[input].empty( ) ) { + Credit *c = _in_cred_buffer[input].front( ); + _in_cred_buffer[input].pop( ); + _input_credits[input]->Send( c ); + } + } +} + +void EventRouter::Display( ostream & os ) const +{ + for ( int input = 0; input < _inputs; ++input ) { + _buf[input]->Display( os ); + } +} + +EventNextVCState::EventNextVCState( const Configuration& config, + Module *parent, const string& name ) : + Module( parent, name ) +{ + _buf_size = config.GetInt( "vc_buf_size" ); + _vcs = config.GetInt( "num_vcs" ); + + _credits.resize(_vcs, _buf_size); + _presence.resize(_vcs, 0); + _input.resize(_vcs); + _inputVC.resize(_vcs); + _waiting.resize(_vcs); + _state.resize(_vcs, idle); +} + +EventNextVCState::eNextVCState EventNextVCState::GetState( int vc ) const +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _state[vc]; +} + +int EventNextVCState::GetPresence( int vc ) const +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _presence[vc]; +} + +int EventNextVCState::GetCredits( int vc ) const +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _credits[vc]; +} + +int EventNextVCState::GetInput( int vc ) const +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _input[vc]; +} + +int EventNextVCState::GetInputVC( int vc ) const +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return _inputVC[vc]; +} + +bool EventNextVCState::IsWaiting( int vc ) const +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + return !_waiting[vc].empty( ); +} + +void EventNextVCState::PushWaiting( int vc, tWaiting *w ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + + if ( w->watch ) { + cout << FullName() << " pushing flit " << w->id + << " onto a waiting queue of length " << _waiting[vc].size( ) << endl; + } + + _waiting[vc].push_back( w ); +} + +void EventNextVCState::IncrWaiting( int vc, int w_input, int w_vc ) +{ + list<tWaiting *>::iterator match; + + // search for match + for ( match = _waiting[vc].begin( ); match != _waiting[vc].end( ); match++ ) { + if ( ( (*match)->input == w_input ) && + ( (*match)->vc == w_vc ) ) break; + } + + if ( match != _waiting[vc].end( ) ) { + (*match)->pres++; + } else { + Error( "Did not find match in IncrWaiting" ); + } +} + +bool EventNextVCState::IsInputWaiting( int vc, int w_input, int w_vc ) const +{ + list<tWaiting *>::const_iterator match; + bool r; + + // search for match + for ( match = _waiting[vc].begin( ); match != _waiting[vc].end( ); match++ ) { + if ( ( (*match)->input == w_input ) && + ( (*match)->vc == w_vc ) ) break; + } + + if ( match != _waiting[vc].end( ) ) { + r = true; + } else { + r = false; + } + + return r; +} + +EventNextVCState::tWaiting *EventNextVCState::PopWaiting( int vc ) +{ + tWaiting *w; + + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + + w = _waiting[vc].front( ); + _waiting[vc].pop_front( ); + + return w; +} + +void EventNextVCState::SetState( int vc, eNextVCState state ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + _state[vc] = state; +} + +void EventNextVCState::SetCredits( int vc, int value ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + _credits[vc] = value; +} + +void EventNextVCState::SetPresence( int vc, int value ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + _presence[vc] = value; +} + +void EventNextVCState::SetInput( int vc, int input ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + _input[vc] = input; +} + +void EventNextVCState::SetInputVC( int vc, int in_vc ) +{ + assert( ( vc >= 0 ) && ( vc < _vcs ) ); + _inputVC[vc] = in_vc; +} diff --git a/src/intersim2/routers/event_router.hpp b/src/intersim2/routers/event_router.hpp new file mode 100644 index 0000000..2f2f170 --- /dev/null +++ b/src/intersim2/routers/event_router.hpp @@ -0,0 +1,187 @@ +// $Id: event_router.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _EVENT_ROUTER_HPP_ +#define _EVENT_ROUTER_HPP_ + +#include <string> +#include <queue> +#include <vector> + +#include "module.hpp" +#include "router.hpp" +#include "buffer.hpp" +#include "vc.hpp" +#include "prio_arb.hpp" +#include "routefunc.hpp" +#include "outputset.hpp" +#include "pipefifo.hpp" + +class EventNextVCState : public Module { +public: + enum eNextVCState { idle, busy, tail_pending }; + + struct tWaiting { + int input; + int vc; + int id; + int pres; + bool watch; + }; + +private: + int _buf_size; + int _vcs; + + vector<int> _credits; + vector<int> _presence; + vector<int> _input; + vector<int> _inputVC; + + vector<list<tWaiting *> > _waiting; + + vector<eNextVCState> _state; + +public: + + EventNextVCState( const Configuration& config, + Module *parent, const string& name ); + + eNextVCState GetState( int vc ) const; + int GetPresence( int vc ) const; + int GetCredits( int vc ) const; + int GetInput( int vc ) const; + int GetInputVC( int vc ) const; + + bool IsWaiting( int vc ) const; + bool IsInputWaiting( int vc, int w_input, int w_vc ) const; + + void PushWaiting( int vc, tWaiting *w ); + void IncrWaiting( int vc, int w_input, int w_vc ); + tWaiting *PopWaiting( int vc ); + + void SetState( int vc, eNextVCState state ); + void SetCredits( int vc, int value ); + void SetPresence( int vc, int value ); + void SetInput( int vc, int input ); + void SetInputVC( int vc, int in_vc ); +}; + +class EventRouter : public Router { + int _vcs; + + int _vct; + + vector<Buffer *> _buf; + vector<vector<bool> > _active; + + tRoutingFunction _rf; + + vector<EventNextVCState *> _output_state; + + PipelineFIFO<Flit> *_crossbar_pipe; + PipelineFIFO<Credit> *_credit_pipe; + + vector<queue<Flit *> > _input_buffer; + vector<queue<Flit *> > _output_buffer; + + vector<queue<Credit *> > _in_cred_buffer; + vector<queue<Credit *> > _out_cred_buffer; + + struct tArrivalEvent { + int input; + int output; + int src_vc; + int dst_vc; + bool head; + bool tail; + + int id; // debug + bool watch; // debug + }; + + PipelineFIFO<tArrivalEvent> *_arrival_pipe; + vector<queue<tArrivalEvent *> > _arrival_queue; + vector<PriorityArbiter*> _arrival_arbiter; + + struct tTransportEvent { + int input; + int src_vc; + int dst_vc; + + int id; // debug + bool watch; // debug + }; + + vector<queue<tTransportEvent *> > _transport_queue; + vector<PriorityArbiter*> _transport_arbiter; + + vector<bool> _transport_free; + vector<int> _transport_match; + + void _ReceiveFlits( ); + void _ReceiveCredits( ); + + void _IncomingFlits( ); + void _ArrivalRequests( int input ); + void _ArrivalArb( int output ); + void _SendTransport( int input, int output, tArrivalEvent *aevt ); + void _ProcessWaiting( int output, int out_vc ); + void _TransportRequests( int output ); + void _TransportArb( int input ); + void _OutputQueuing( ); + + void _SendFlits( ); + void _SendCredits( ); + + virtual void _InternalStep( ); + +public: + EventRouter( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ); + virtual ~EventRouter( ); + + virtual void ReadInputs( ); + virtual void WriteOutputs( ); + + virtual int GetUsedCredit(int o) const {return 0;} + virtual int GetBufferOccupancy(int i) const {return 0;} + +#ifdef TRACK_BUFFERS + virtual int GetUsedCreditForClass(int output, int cl) const {return 0;} + virtual int GetBufferOccupancyForClass(int input, int cl) const {return 0;} +#endif + + virtual vector<int> UsedCredits() const { return vector<int>(); } + virtual vector<int> FreeCredits() const { return vector<int>(); } + virtual vector<int> MaxCredits() const { return vector<int>(); } + + void Display( ostream & os = cout ) const; +}; + +#endif diff --git a/src/intersim2/routers/iq_router.cpp b/src/intersim2/routers/iq_router.cpp new file mode 100644 index 0000000..d97f485 --- /dev/null +++ b/src/intersim2/routers/iq_router.cpp @@ -0,0 +1,2385 @@ +// $Id: iq_router.cpp 5263 2012-09-20 23:40:33Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include "iq_router.hpp" + +#include <string> +#include <sstream> +#include <iostream> +#include <iomanip> +#include <cstdlib> +#include <cassert> +#include <limits> + +#include "globals.hpp" +#include "random_utils.hpp" +#include "vc.hpp" +#include "routefunc.hpp" +#include "outputset.hpp" +#include "buffer.hpp" +#include "buffer_state.hpp" +#include "roundrobin_arb.hpp" +#include "allocator.hpp" +#include "switch_monitor.hpp" +#include "buffer_monitor.hpp" + +IQRouter::IQRouter( Configuration const & config, Module *parent, + string const & name, int id, int inputs, int outputs ) +: Router( config, parent, name, id, inputs, outputs ), _active(false) +{ + _vcs = config.GetInt( "num_vcs" ); + + _vc_busy_when_full = (config.GetInt("vc_busy_when_full") > 0); + _vc_prioritize_empty = (config.GetInt("vc_prioritize_empty") > 0); + _vc_shuffle_requests = (config.GetInt("vc_shuffle_requests") > 0); + + _speculative = (config.GetInt("speculative") > 0); + _spec_check_elig = (config.GetInt("spec_check_elig") > 0); + _spec_check_cred = (config.GetInt("spec_check_cred") > 0); + _spec_mask_by_reqs = (config.GetInt("spec_mask_by_reqs") > 0); + + _routing_delay = config.GetInt( "routing_delay" ); + _vc_alloc_delay = config.GetInt( "vc_alloc_delay" ); + if(!_vc_alloc_delay) { + Error("VC allocator cannot have zero delay."); + } + _sw_alloc_delay = config.GetInt( "sw_alloc_delay" ); + if(!_sw_alloc_delay) { + Error("Switch allocator cannot have zero delay."); + } + + // Routing + string const rf = config.GetStr("routing_function") + "_" + config.GetStr("topology"); + map<string, tRoutingFunction>::const_iterator rf_iter = gRoutingFunctionMap.find(rf); + if(rf_iter == gRoutingFunctionMap.end()) { + Error("Invalid routing function: " + rf); + } + _rf = rf_iter->second; + + // Alloc VC's + _buf.resize(_inputs); + for ( int i = 0; i < _inputs; ++i ) { + ostringstream module_name; + module_name << "buf_" << i; + _buf[i] = new Buffer(config, _outputs, this, module_name.str( ) ); + module_name.str(""); + } + + // Alloc next VCs' buffer state + _next_buf.resize(_outputs); + for (int j = 0; j < _outputs; ++j) { + ostringstream module_name; + module_name << "next_vc_o" << j; + _next_buf[j] = new BufferState( config, this, module_name.str( ) ); + module_name.str(""); + } + + // Alloc allocators + string vc_alloc_type = config.GetStr( "vc_allocator" ); + if(vc_alloc_type == "piggyback") { + if(!_speculative) { + Error("Piggyback VC allocation requires speculative switch allocation to be enabled."); + } + _vc_allocator = NULL; + _vc_rr_offset.resize(_outputs*_classes, -1); + } else { + _vc_allocator = Allocator::NewAllocator( this, "vc_allocator", + vc_alloc_type, + _vcs*_inputs, + _vcs*_outputs ); + + if ( !_vc_allocator ) { + Error("Unknown vc_allocator type: " + vc_alloc_type); + } + } + + string sw_alloc_type = config.GetStr( "sw_allocator" ); + _sw_allocator = Allocator::NewAllocator( this, "sw_allocator", + sw_alloc_type, + _inputs*_input_speedup, + _outputs*_output_speedup ); + + if ( !_sw_allocator ) { + Error("Unknown sw_allocator type: " + sw_alloc_type); + } + + string spec_sw_alloc_type = config.GetStr( "spec_sw_allocator" ); + if ( _speculative && ( spec_sw_alloc_type != "prio" ) ) { + _spec_sw_allocator = Allocator::NewAllocator( this, "spec_sw_allocator", + spec_sw_alloc_type, + _inputs*_input_speedup, + _outputs*_output_speedup ); + if ( !_spec_sw_allocator ) { + Error("Unknown spec_sw_allocator type: " + spec_sw_alloc_type); + } + } else { + _spec_sw_allocator = NULL; + } + + _sw_rr_offset.resize(_inputs*_input_speedup); + for(int i = 0; i < _inputs*_input_speedup; ++i) + _sw_rr_offset[i] = i % _input_speedup; + + _noq = config.GetInt("noq") > 0; + if(_noq) { + if(_routing_delay) { + Error("NOQ requires lookahead routing to be enabled."); + } + if(_vcs < _outputs) { + Error("NOQ requires at least as many VCs as router outputs."); + } + } + _noq_next_output_port.resize(_inputs, vector<int>(_vcs, -1)); + _noq_next_vc_start.resize(_inputs, vector<int>(_vcs, -1)); + _noq_next_vc_end.resize(_inputs, vector<int>(_vcs, -1)); + + // Output queues + _output_buffer_size = config.GetInt("output_buffer_size"); + _output_buffer.resize(_outputs); + _credit_buffer.resize(_inputs); + + // Switch configuration (when held for multiple cycles) + _hold_switch_for_packet = (config.GetInt("hold_switch_for_packet") > 0); + _switch_hold_in.resize(_inputs*_input_speedup, -1); + _switch_hold_out.resize(_outputs*_output_speedup, -1); + _switch_hold_vc.resize(_inputs*_input_speedup, -1); + + _bufferMonitor = new BufferMonitor(inputs, _classes); + _switchMonitor = new SwitchMonitor(inputs, outputs, _classes); + +#ifdef TRACK_FLOWS + for(int c = 0; c < _classes; ++c) { + _stored_flits[c].resize(_inputs, 0); + _active_packets[c].resize(_inputs, 0); + } + _outstanding_classes.resize(_outputs, vector<queue<int> >(_vcs)); +#endif +} + +IQRouter::~IQRouter( ) +{ + + if(gPrintActivity) { + cout << Name() << ".bufferMonitor:" << endl ; + cout << *_bufferMonitor << endl ; + + cout << Name() << ".switchMonitor:" << endl ; + cout << "Inputs=" << _inputs ; + cout << "Outputs=" << _outputs ; + cout << *_switchMonitor << endl ; + } + + for(int i = 0; i < _inputs; ++i) + delete _buf[i]; + + for(int j = 0; j < _outputs; ++j) + delete _next_buf[j]; + + delete _vc_allocator; + delete _sw_allocator; + if(_spec_sw_allocator) + delete _spec_sw_allocator; + + delete _bufferMonitor; + delete _switchMonitor; +} + +void IQRouter::AddOutputChannel(FlitChannel * channel, CreditChannel * backchannel) +{ + int alloc_delay = _speculative ? max(_vc_alloc_delay, _sw_alloc_delay) : (_vc_alloc_delay + _sw_alloc_delay); + int min_latency = 1 + _crossbar_delay + channel->GetLatency() + _routing_delay + alloc_delay + backchannel->GetLatency() + _credit_delay; + _next_buf[_output_channels.size()]->SetMinLatency(min_latency); + Router::AddOutputChannel(channel, backchannel); +} + +void IQRouter::ReadInputs( ) +{ + bool have_flits = _ReceiveFlits( ); + bool have_credits = _ReceiveCredits( ); + _active = _active || have_flits || have_credits; +} + +void IQRouter::_InternalStep( ) +{ + if(!_active) { + return; + } + + _InputQueuing( ); + bool activity = !_proc_credits.empty(); + + if(!_route_vcs.empty()) + _RouteEvaluate( ); + if(_vc_allocator) { + _vc_allocator->Clear(); + if(!_vc_alloc_vcs.empty()) + _VCAllocEvaluate( ); + } + if(_hold_switch_for_packet) { + if(!_sw_hold_vcs.empty()) + _SWHoldEvaluate( ); + } + _sw_allocator->Clear(); + if(_spec_sw_allocator) + _spec_sw_allocator->Clear(); + if(!_sw_alloc_vcs.empty()) + _SWAllocEvaluate( ); + if(!_crossbar_flits.empty()) + _SwitchEvaluate( ); + + if(!_route_vcs.empty()) { + _RouteUpdate( ); + activity = activity || !_route_vcs.empty(); + } + if(!_vc_alloc_vcs.empty()) { + _VCAllocUpdate( ); + activity = activity || !_vc_alloc_vcs.empty(); + } + if(_hold_switch_for_packet) { + if(!_sw_hold_vcs.empty()) { + _SWHoldUpdate( ); + activity = activity || !_sw_hold_vcs.empty(); + } + } + if(!_sw_alloc_vcs.empty()) { + _SWAllocUpdate( ); + activity = activity || !_sw_alloc_vcs.empty(); + } + if(!_crossbar_flits.empty()) { + _SwitchUpdate( ); + activity = activity || !_crossbar_flits.empty(); + } + + _active = activity; + + _OutputQueuing( ); + + _bufferMonitor->cycle( ); + _switchMonitor->cycle( ); +} + +void IQRouter::WriteOutputs( ) +{ + _SendFlits( ); + _SendCredits( ); +} + + +//------------------------------------------------------------------------------ +// read inputs +//------------------------------------------------------------------------------ + +bool IQRouter::_ReceiveFlits( ) +{ + bool activity = false; + for(int input = 0; input < _inputs; ++input) { + Flit * const f = _input_channels[input]->Receive(); + if(f) { + +#ifdef TRACK_FLOWS + ++_received_flits[f->cl][input]; +#endif + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Received flit " << f->id + << " from channel at input " << input + << "." << endl; + } + _in_queue_flits.insert(make_pair(input, f)); + activity = true; + } + } + return activity; +} + +bool IQRouter::_ReceiveCredits( ) +{ + bool activity = false; + for(int output = 0; output < _outputs; ++output) { + Credit * const c = _output_credits[output]->Receive(); + if(c) { + _proc_credits.push_back(make_pair(GetSimTime() + _credit_delay, + make_pair(c, output))); + activity = true; + } + } + return activity; +} + + +//------------------------------------------------------------------------------ +// input queuing +//------------------------------------------------------------------------------ + +void IQRouter::_InputQueuing( ) +{ + for(map<int, Flit *>::const_iterator iter = _in_queue_flits.begin(); + iter != _in_queue_flits.end(); + ++iter) { + + int const input = iter->first; + assert((input >= 0) && (input < _inputs)); + + Flit * const f = iter->second; + assert(f); + + int const vc = f->vc; + assert((vc >= 0) && (vc < _vcs)); + + Buffer * const cur_buf = _buf[input]; + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Adding flit " << f->id + << " to VC " << vc + << " at input " << input + << " (state: " << VC::VCSTATE[cur_buf->GetState(vc)]; + if(cur_buf->Empty(vc)) { + *gWatchOut << ", empty"; + } else { + assert(cur_buf->FrontFlit(vc)); + *gWatchOut << ", front: " << cur_buf->FrontFlit(vc)->id; + } + *gWatchOut << ")." << endl; + } + cur_buf->AddFlit(vc, f); + +#ifdef TRACK_FLOWS + ++_stored_flits[f->cl][input]; + if(f->head) ++_active_packets[f->cl][input]; +#endif + + _bufferMonitor->write(input, f) ; + + if(cur_buf->GetState(vc) == VC::idle) { + assert(cur_buf->FrontFlit(vc) == f); + assert(cur_buf->GetOccupancy(vc) == 1); + assert(f->head); + assert(_switch_hold_vc[input*_input_speedup + vc%_input_speedup] != vc); + if(_routing_delay) { + cur_buf->SetState(vc, VC::routing); + _route_vcs.push_back(make_pair(-1, make_pair(input, vc))); + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Using precomputed lookahead routing information for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + cur_buf->SetRouteSet(vc, &f->la_route_set); + cur_buf->SetState(vc, VC::vc_alloc); + if(_speculative) { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc), + -1))); + } + if(_vc_allocator) { + _vc_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc), + -1))); + } + if(_noq) { + _UpdateNOQ(input, vc, f); + } + } + } else if((cur_buf->GetState(vc) == VC::active) && + (cur_buf->FrontFlit(vc) == f)) { + if(_switch_hold_vc[input*_input_speedup + vc%_input_speedup] == vc) { + _sw_hold_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc), + -1))); + } else { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(make_pair(input, vc), + -1))); + } + } + } + _in_queue_flits.clear(); + + while(!_proc_credits.empty()) { + + pair<int, pair<Credit *, int> > const & item = _proc_credits.front(); + + int const time = item.first; + if(GetSimTime() < time) { + break; + } + + Credit * const c = item.second.first; + assert(c); + + int const output = item.second.second; + assert((output >= 0) && (output < _outputs)); + + BufferState * const dest_buf = _next_buf[output]; + +#ifdef TRACK_FLOWS + for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) { + int const vc = *iter; + assert(!_outstanding_classes[output][vc].empty()); + int cl = _outstanding_classes[output][vc].front(); + _outstanding_classes[output][vc].pop(); + assert(_outstanding_credits[cl][output] > 0); + --_outstanding_credits[cl][output]; + } +#endif + + dest_buf->ProcessCredit(c); + c->Free(); + _proc_credits.pop_front(); + } +} + + +//------------------------------------------------------------------------------ +// routing +//------------------------------------------------------------------------------ + +void IQRouter::_RouteEvaluate( ) +{ + assert(_routing_delay); + + for(deque<pair<int, pair<int, int> > >::iterator iter = _route_vcs.begin(); + iter != _route_vcs.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + iter->first = GetSimTime() + _routing_delay - 1; + + int const input = iter->second.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.second; + assert((vc >= 0) && (vc < _vcs)); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::routing); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + assert(f->head); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Beginning routing for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + } +} + +void IQRouter::_RouteUpdate( ) +{ + assert(_routing_delay); + + while(!_route_vcs.empty()) { + + pair<int, pair<int, int> > const & item = _route_vcs.front(); + + int const time = item.first; + if((time < 0) || (GetSimTime() < time)) { + break; + } + assert(GetSimTime() == time); + + int const input = item.second.first; + assert((input >= 0) && (input < _inputs)); + int const vc = item.second.second; + assert((vc >= 0) && (vc < _vcs)); + + Buffer * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::routing); + + Flit * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + assert(f->head); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Completed routing for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + cur_buf->Route(vc, _rf, this, f, input); + cur_buf->SetState(vc, VC::vc_alloc); + if(_speculative) { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second, -1))); + } + if(_vc_allocator) { + _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second, -1))); + } + // NOTE: No need to handle NOQ here, as it requires lookahead routing! + _route_vcs.pop_front(); + } +} + + +//------------------------------------------------------------------------------ +// VC allocation +//------------------------------------------------------------------------------ + +void IQRouter::_VCAllocEvaluate( ) +{ + assert(_vc_allocator); + + bool watched = false; + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin(); + iter != _vc_alloc_vcs.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + assert(iter->second.second == -1); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::vc_alloc); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + assert(f->head); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Beginning VC allocation for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + OutputSet const * const route_set = cur_buf->GetRouteSet(vc); + assert(route_set); + + int const out_priority = cur_buf->GetPriority(vc); + set<OutputSet::sSetElement> const setlist = route_set->GetSet(); + + bool elig = false; + bool cred = false; + bool reserved = false; + + assert(!_noq || (setlist.size() == 1)); + + for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin(); + iset != setlist.end(); + ++iset) { + + int const out_port = iset->output_port; + assert((out_port >= 0) && (out_port < _outputs)); + + BufferState const * const dest_buf = _next_buf[out_port]; + + int vc_start; + int vc_end; + + if(_noq && _noq_next_output_port[input][vc] >= 0) { + assert(!_routing_delay); + vc_start = _noq_next_vc_start[input][vc]; + vc_end = _noq_next_vc_end[input][vc]; + } else { + vc_start = iset->vc_start; + vc_end = iset->vc_end; + } + assert(vc_start >= 0 && vc_start < _vcs); + assert(vc_end >= 0 && vc_end < _vcs); + assert(vc_end >= vc_start); + + for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) { + assert((out_vc >= 0) && (out_vc < _vcs)); + + int in_priority = iset->pri; + if(_vc_prioritize_empty && !dest_buf->IsEmptyFor(out_vc)) { + assert(in_priority >= 0); + in_priority += numeric_limits<int>::min(); + } + + // On the input input side, a VC might request several output VCs. + // These VCs can be prioritized by the routing function, and this is + // reflected in "in_priority". On the output side, if multiple VCs are + // requesting the same output VC, the priority of VCs is based on the + // actual packet priorities, which is reflected in "out_priority". + + if(!dest_buf->IsAvailableFor(out_vc)) { + if(f->watch) { + int const use_input_and_vc = dest_buf->UsedBy(out_vc); + int const use_input = use_input_and_vc / _vcs; + int const use_vc = use_input_and_vc % _vcs; + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " VC " << out_vc + << " at output " << out_port + << " is in use by VC " << use_vc + << " at input " << use_input; + Flit * cf = _buf[use_input]->FrontFlit(use_vc); + if(cf) { + *gWatchOut << " (front flit: " << cf->id << ")"; + } else { + *gWatchOut << " (empty)"; + } + *gWatchOut << "." << endl; + } + } else { + elig = true; + if(_vc_busy_when_full && dest_buf->IsFullFor(out_vc)) { + if(f->watch) + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " VC " << out_vc + << " at output " << out_port + << " is full." << endl; + reserved |= !dest_buf->IsFull(); + } else { + cred = true; + if(f->watch){ + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Requesting VC " << out_vc + << " at output " << out_port + << " (in_pri: " << in_priority + << ", out_pri: " << out_priority + << ")." << endl; + watched = true; + } + int const input_and_vc + = _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc); + _vc_allocator->AddRequest(input_and_vc, out_port*_vcs + out_vc, + 0, in_priority, out_priority); + } + } + } + } + if(!elig) { + iter->second.second = STALL_BUFFER_BUSY; + } else if(_vc_busy_when_full && !cred) { + iter->second.second = reserved ? STALL_BUFFER_RESERVED : STALL_BUFFER_FULL; + } + } + + if(watched) { + *gWatchOut << GetSimTime() << " | " << _vc_allocator->FullName() << " | "; + _vc_allocator->PrintRequests( gWatchOut ); + } + + _vc_allocator->Allocate(); + + if(watched) { + *gWatchOut << GetSimTime() << " | " << _vc_allocator->FullName() << " | "; + _vc_allocator->PrintGrants( gWatchOut ); + } + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin(); + iter != _vc_alloc_vcs.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + iter->first = GetSimTime() + _vc_alloc_delay - 1; + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + if(iter->second.second < -1) { + continue; + } + + assert(iter->second.second == -1); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::vc_alloc); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + assert(f->head); + + int const input_and_vc + = _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc); + int const output_and_vc = _vc_allocator->OutputAssigned(input_and_vc); + + if(output_and_vc >= 0) { + + int const match_output = output_and_vc / _vcs; + assert((match_output >= 0) && (match_output < _outputs)); + int const match_vc = output_and_vc % _vcs; + assert((match_vc >= 0) && (match_vc < _vcs)); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Assigning VC " << match_vc + << " at output " << match_output + << " to VC " << vc + << " at input " << input + << "." << endl; + } + + iter->second.second = output_and_vc; + + } else { + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "VC allocation failed for VC " << vc + << " at input " << input + << "." << endl; + } + + iter->second.second = STALL_BUFFER_CONFLICT; + + } + } + + if(_vc_alloc_delay <= 1) { + return; + } + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _vc_alloc_vcs.begin(); + iter != _vc_alloc_vcs.end(); + ++iter) { + + int const time = iter->first; + assert(time >= 0); + if(GetSimTime() < time) { + break; + } + + assert(iter->second.second != -1); + + int const output_and_vc = iter->second.second; + + if(output_and_vc >= 0) { + + int const match_output = output_and_vc / _vcs; + assert((match_output >= 0) && (match_output < _outputs)); + int const match_vc = output_and_vc % _vcs; + assert((match_vc >= 0) && (match_vc < _vcs)); + + BufferState const * const dest_buf = _next_buf[match_output]; + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::vc_alloc); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + assert(f->head); + + if(!dest_buf->IsAvailableFor(match_vc)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Discarding previously generated grant for VC " << vc + << " at input " << input + << ": VC " << match_vc + << " at output " << match_output + << " is no longer available." << endl; + } + iter->second.second = STALL_BUFFER_BUSY; + } else if(_vc_busy_when_full && dest_buf->IsFullFor(match_vc)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Discarding previously generated grant for VC " << vc + << " at input " << input + << ": VC " << match_vc + << " at output " << match_output + << " has become full." << endl; + } + iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED; + } + } + } +} + +void IQRouter::_VCAllocUpdate( ) +{ + assert(_vc_allocator); + + while(!_vc_alloc_vcs.empty()) { + + pair<int, pair<pair<int, int>, int> > const & item = _vc_alloc_vcs.front(); + + int const time = item.first; + if((time < 0) || (GetSimTime() < time)) { + break; + } + assert(GetSimTime() == time); + + int const input = item.second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = item.second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + assert(item.second.second != -1); + + Buffer * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::vc_alloc); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + assert(f->head); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Completed VC allocation for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + int const output_and_vc = item.second.second; + + if(output_and_vc >= 0) { + + int const match_output = output_and_vc / _vcs; + assert((match_output >= 0) && (match_output < _outputs)); + int const match_vc = output_and_vc % _vcs; + assert((match_vc >= 0) && (match_vc < _vcs)); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Acquiring assigned VC " << match_vc + << " at output " << match_output + << "." << endl; + } + + BufferState * const dest_buf = _next_buf[match_output]; + assert(dest_buf->IsAvailableFor(match_vc)); + + dest_buf->TakeBuffer(match_vc, input*_vcs + vc); + + cur_buf->SetOutput(vc, match_output, match_vc); + cur_buf->SetState(vc, VC::active); + if(!_speculative) { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1))); + } + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " No output VC allocated." << endl; + } + +#ifdef TRACK_STALLS + assert((output_and_vc == STALL_BUFFER_BUSY) || + (output_and_vc == STALL_BUFFER_CONFLICT)); + if(output_and_vc == STALL_BUFFER_BUSY) { + ++_buffer_busy_stalls[f->cl]; + } else if(output_and_vc == STALL_BUFFER_CONFLICT) { + ++_buffer_conflict_stalls[f->cl]; + } +#endif + + _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1))); + } + _vc_alloc_vcs.pop_front(); + } +} + + +//------------------------------------------------------------------------------ +// switch holding +//------------------------------------------------------------------------------ + +void IQRouter::_SWHoldEvaluate( ) +{ + assert(_hold_switch_for_packet); + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_hold_vcs.begin(); + iter != _sw_hold_vcs.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + iter->first = GetSimTime(); + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + assert(iter->second.second == -1); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::active); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Beginning held switch allocation for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + int const expanded_input = input * _input_speedup + vc % _input_speedup; + assert(_switch_hold_vc[expanded_input] == vc); + + int const match_port = cur_buf->GetOutputPort(vc); + assert((match_port >= 0) && (match_port < _outputs)); + int const match_vc = cur_buf->GetOutputVC(vc); + assert((match_vc >= 0) && (match_vc < _vcs)); + + int const expanded_output = match_port*_output_speedup + input%_output_speedup; + assert(_switch_hold_in[expanded_input] == expanded_output); + + BufferState const * const dest_buf = _next_buf[match_port]; + + if(dest_buf->IsFullFor(match_vc)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Unable to reuse held connection from input " << input + << "." << (expanded_input % _input_speedup) + << " to output " << match_port + << "." << (expanded_output % _output_speedup) + << ": No credit available." << endl; + } + iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED; + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Reusing held connection from input " << input + << "." << (expanded_input % _input_speedup) + << " to output " << match_port + << "." << (expanded_output % _output_speedup) + << "." << endl; + } + iter->second.second = expanded_output; + } + } +} + +void IQRouter::_SWHoldUpdate( ) +{ + assert(_hold_switch_for_packet); + + while(!_sw_hold_vcs.empty()) { + + pair<int, pair<pair<int, int>, int> > const & item = _sw_hold_vcs.front(); + + int const time = item.first; + if(time < 0) { + break; + } + assert(GetSimTime() == time); + + int const input = item.second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = item.second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + assert(item.second.second != -1); + + Buffer * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert(cur_buf->GetState(vc) == VC::active); + + Flit * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Completed held switch allocation for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + int const expanded_input = input * _input_speedup + vc % _input_speedup; + assert(_switch_hold_vc[expanded_input] == vc); + + int const expanded_output = item.second.second; + + if(expanded_output >= 0 && ( _output_buffer_size==-1 || _output_buffer[expanded_output].size()<size_t(_output_buffer_size))) { + + assert(_switch_hold_in[expanded_input] == expanded_output); + assert(_switch_hold_out[expanded_output] == expanded_input); + + int const output = expanded_output / _output_speedup; + assert((output >= 0) && (output < _outputs)); + assert(cur_buf->GetOutputPort(vc) == output); + + int const match_vc = cur_buf->GetOutputVC(vc); + assert((match_vc >= 0) && (match_vc < _vcs)); + + BufferState * const dest_buf = _next_buf[output]; + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Scheduling switch connection from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << "." << endl; + } + + cur_buf->RemoveFlit(vc); + +#ifdef TRACK_FLOWS + --_stored_flits[f->cl][input]; + if(f->tail) --_active_packets[f->cl][input]; +#endif + + _bufferMonitor->read(input, f) ; + + f->hops++; + f->vc = match_vc; + + if(!_routing_delay && f->head) { + const FlitChannel * channel = _output_channels[output]; + const Router * router = channel->GetSink(); + if(router) { + if(_noq) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Updating lookahead routing information for flit " << f->id + << " (NOQ)." << endl; + } + int next_output_port = _noq_next_output_port[input][vc]; + assert(next_output_port >= 0); + _noq_next_output_port[input][vc] = -1; + int next_vc_start = _noq_next_vc_start[input][vc]; + assert(next_vc_start >= 0 && next_vc_start < _vcs); + _noq_next_vc_start[input][vc] = -1; + int next_vc_end = _noq_next_vc_end[input][vc]; + assert(next_vc_end >= 0 && next_vc_end < _vcs); + _noq_next_vc_end[input][vc] = -1; + f->la_route_set.Clear(); + f->la_route_set.AddRange(next_output_port, next_vc_start, next_vc_end); + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Updating lookahead routing information for flit " << f->id + << "." << endl; + } + int in_channel = channel->GetSinkPort(); + _rf(router, f, in_channel, &f->la_route_set, false); + } + } else { + f->la_route_set.Clear(); + } + } + +#ifdef TRACK_FLOWS + ++_outstanding_credits[f->cl][output]; + _outstanding_classes[output][f->vc].push(f->cl); +#endif + + dest_buf->SendingFlit(f); + + _crossbar_flits.push_back(make_pair(-1, make_pair(f, make_pair(expanded_input, expanded_output)))); + + if(_out_queue_credits.count(input) == 0) { + _out_queue_credits.insert(make_pair(input, Credit::New())); + } + _out_queue_credits.find(input)->second->vc.insert(vc); + + if(cur_buf->Empty(vc)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Cancelling held connection from input " << input + << "." << (expanded_input % _input_speedup) + << " to " << output + << "." << (expanded_output % _output_speedup) + << ": No more flits." << endl; + } + _switch_hold_vc[expanded_input] = -1; + _switch_hold_in[expanded_input] = -1; + _switch_hold_out[expanded_output] = -1; + if(f->tail) { + cur_buf->SetState(vc, VC::idle); + } + } else { + Flit * const nf = cur_buf->FrontFlit(vc); + assert(nf); + assert(nf->vc == vc); + if(f->tail) { + assert(nf->head); + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Cancelling held connection from input " << input + << "." << (expanded_input % _input_speedup) + << " to " << output + << "." << (expanded_output % _output_speedup) + << ": End of packet." << endl; + } + _switch_hold_vc[expanded_input] = -1; + _switch_hold_in[expanded_input] = -1; + _switch_hold_out[expanded_output] = -1; + if(_routing_delay) { + cur_buf->SetState(vc, VC::routing); + _route_vcs.push_back(make_pair(-1, item.second.first)); + } else { + if(nf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Using precomputed lookahead routing information for VC " << vc + << " at input " << input + << " (front: " << nf->id + << ")." << endl; + } + cur_buf->SetRouteSet(vc, &nf->la_route_set); + cur_buf->SetState(vc, VC::vc_alloc); + if(_speculative) { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + if(_vc_allocator) { + _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + if(_noq) { + _UpdateNOQ(input, vc, nf); + } + } + } else { + _sw_hold_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + } + } else { + //when internal speedup >1.0, the buffer stall stats may not be accruate + assert((expanded_output == STALL_BUFFER_FULL) || + (expanded_output == STALL_BUFFER_RESERVED) || !( _output_buffer_size==-1 || _output_buffer[expanded_output].size()<size_t(_output_buffer_size))); + + int const held_expanded_output = _switch_hold_in[expanded_input]; + assert(held_expanded_output >= 0); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Cancelling held connection from input " << input + << "." << (expanded_input % _input_speedup) + << " to " << (held_expanded_output / _output_speedup) + << "." << (held_expanded_output % _output_speedup) + << ": Flit not sent." << endl; + } + _switch_hold_vc[expanded_input] = -1; + _switch_hold_in[expanded_input] = -1; + _switch_hold_out[held_expanded_output] = -1; + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + _sw_hold_vcs.pop_front(); + } +} + + +//------------------------------------------------------------------------------ +// switch allocation +//------------------------------------------------------------------------------ + +bool IQRouter::_SWAllocAddReq(int input, int vc, int output) +{ + assert(input >= 0 && input < _inputs); + assert(vc >= 0 && vc < _vcs); + assert(output >= 0 && output < _outputs); + + // When input_speedup > 1, the virtual channel buffers are interleaved to + // create multiple input ports to the switch. Similarily, the output ports + // are interleaved based on their originating input when output_speedup > 1. + + int const expanded_input = input * _input_speedup + vc % _input_speedup; + int const expanded_output = output * _output_speedup + input % _output_speedup; + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert((cur_buf->GetState(vc) == VC::active) || + (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc))); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + if((_switch_hold_in[expanded_input] < 0) && + (_switch_hold_out[expanded_output] < 0)) { + + Allocator * allocator = _sw_allocator; + int prio = cur_buf->GetPriority(vc); + + if(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)) { + if(_spec_sw_allocator) { + allocator = _spec_sw_allocator; + } else { + assert(prio >= 0); + prio += numeric_limits<int>::min(); + } + } + + Allocator::sRequest req; + + if(allocator->ReadRequest(req, expanded_input, expanded_output)) { + if(RoundRobinArbiter::Supersedes(vc, prio, req.label, req.in_pri, + _sw_rr_offset[expanded_input], _vcs)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Replacing earlier request from VC " << req.label + << " for output " << output + << "." << (expanded_output % _output_speedup) + << " with priority " << req.in_pri + << " (" << ((cur_buf->GetState(vc) == VC::active) ? + "non-spec" : + "spec") + << ", pri: " << prio + << ")." << endl; + } + allocator->RemoveRequest(expanded_input, expanded_output, req.label); + allocator->AddRequest(expanded_input, expanded_output, vc, prio, prio); + return true; + } + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Output " << output + << "." << (expanded_output % _output_speedup) + << " was already requested by VC " << req.label + << " with priority " << req.in_pri + << " (pri: " << prio + << ")." << endl; + } + return false; + } + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Requesting output " << output + << "." << (expanded_output % _output_speedup) + << " (" << ((cur_buf->GetState(vc) == VC::active) ? + "non-spec" : + "spec") + << ", pri: " << prio + << ")." << endl; + } + allocator->AddRequest(expanded_input, expanded_output, vc, prio, prio); + return true; + } + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Ignoring output " << output + << "." << (expanded_output % _output_speedup) + << " due to switch hold ("; + if(_switch_hold_in[expanded_input] >= 0) { + *gWatchOut << "input: " << input + << "." << (expanded_input % _input_speedup); + if(_switch_hold_out[expanded_output] >= 0) { + *gWatchOut << ", "; + } + } + if(_switch_hold_out[expanded_output] >= 0) { + *gWatchOut << "output: " << output + << "." << (expanded_output % _output_speedup); + } + *gWatchOut << ")." << endl; + } + return false; +} + +void IQRouter::_SWAllocEvaluate( ) +{ + bool watched = false; + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin(); + iter != _sw_alloc_vcs.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + assert(iter->second.second == -1); + + assert(_switch_hold_vc[input * _input_speedup + vc % _input_speedup] != vc); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert((cur_buf->GetState(vc) == VC::active) || + (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc))); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Beginning switch allocation for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + if(cur_buf->GetState(vc) == VC::active) { + + int const dest_output = cur_buf->GetOutputPort(vc); + assert((dest_output >= 0) && (dest_output < _outputs)); + int const dest_vc = cur_buf->GetOutputVC(vc); + assert((dest_vc >= 0) && (dest_vc < _vcs)); + + BufferState const * const dest_buf = _next_buf[dest_output]; + + if(dest_buf->IsFullFor(dest_vc) || ( _output_buffer_size!=-1 && _output_buffer[dest_output].size()>=(size_t)(_output_buffer_size))) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " VC " << dest_vc + << " at output " << dest_output + << " is full." << endl; + } + iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED; + continue; + } + bool const requested = _SWAllocAddReq(input, vc, dest_output); + watched |= requested && f->watch; + continue; + } + assert(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)); + assert(f->head); + + // The following models the speculative VC allocation aspects of the + // pipeline. An input VC with a request in for an egress virtual channel + // will also speculatively bid for the switch regardless of whether the VC + // allocation succeeds. + + OutputSet const * const route_set = cur_buf->GetRouteSet(vc); + assert(route_set); + + set<OutputSet::sSetElement> const setlist = route_set->GetSet(); + + assert(!_noq || (setlist.size() == 1)); + + for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin(); + iset != setlist.end(); + ++iset) { + + int const dest_output = iset->output_port; + assert((dest_output >= 0) && (dest_output < _outputs)); + + // for lower levels of speculation, ignore credit availability and always + // issue requests for all output ports in route set + + BufferState const * const dest_buf = _next_buf[dest_output]; + + bool elig = false; + bool cred = false; + + if(_spec_check_elig) { + + // for higher levels of speculation, check if at least one suitable VC + // is available at the current output + + int vc_start; + int vc_end; + + if(_noq && _noq_next_output_port[input][vc] >= 0) { + assert(!_routing_delay); + vc_start = _noq_next_vc_start[input][vc]; + vc_end = _noq_next_vc_end[input][vc]; + } else { + vc_start = iset->vc_start; + vc_end = iset->vc_end; + } + assert(vc_start >= 0 && vc_start < _vcs); + assert(vc_end >= 0 && vc_end < _vcs); + assert(vc_end >= vc_start); + + for(int dest_vc = vc_start; dest_vc <= vc_end; ++dest_vc) { + assert((dest_vc >= 0) && (dest_vc < _vcs)); + + if(dest_buf->IsAvailableFor(dest_vc) && ( _output_buffer_size==-1 || _output_buffer[dest_output].size()<(size_t)(_output_buffer_size))) { + elig = true; + if(!_spec_check_cred || !dest_buf->IsFullFor(dest_vc)) { + cred = true; + break; + } + } + } + } + + if(_spec_check_elig && !elig) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Output " << dest_output + << " has no suitable VCs available." << endl; + } + iter->second.second = STALL_BUFFER_BUSY; + } else if(_spec_check_cred && !cred) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " All suitable VCs at output " << dest_output + << " are full." << endl; + } + iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED; + } else { + bool const requested = _SWAllocAddReq(input, vc, dest_output); + watched |= requested && f->watch; + } + } + } + + if(watched) { + *gWatchOut << GetSimTime() << " | " << _sw_allocator->FullName() << " | "; + _sw_allocator->PrintRequests(gWatchOut); + if(_spec_sw_allocator) { + *gWatchOut << GetSimTime() << " | " << _spec_sw_allocator->FullName() << " | "; + _spec_sw_allocator->PrintRequests(gWatchOut); + } + } + + _sw_allocator->Allocate(); + if(_spec_sw_allocator) + _spec_sw_allocator->Allocate(); + + if(watched) { + *gWatchOut << GetSimTime() << " | " << _sw_allocator->FullName() << " | "; + _sw_allocator->PrintGrants(gWatchOut); + if(_spec_sw_allocator) { + *gWatchOut << GetSimTime() << " | " << _spec_sw_allocator->FullName() << " | "; + _spec_sw_allocator->PrintGrants(gWatchOut); + } + } + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin(); + iter != _sw_alloc_vcs.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + iter->first = GetSimTime() + _sw_alloc_delay - 1; + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + if(iter->second.second < -1) { + continue; + } + + assert(iter->second.second == -1); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert((cur_buf->GetState(vc) == VC::active) || + (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc))); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + int const expanded_input = input * _input_speedup + vc % _input_speedup; + + int expanded_output = _sw_allocator->OutputAssigned(expanded_input); + + if(expanded_output >= 0) { + assert((expanded_output % _output_speedup) == (input % _output_speedup)); + int const granted_vc = _sw_allocator->ReadRequest(expanded_input, expanded_output); + if(granted_vc == vc) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Assigning output " << (expanded_output / _output_speedup) + << "." << (expanded_output % _output_speedup) + << " to VC " << vc + << " at input " << input + << "." << (vc % _input_speedup) + << "." << endl; + } + _sw_rr_offset[expanded_input] = (vc + _input_speedup) % _vcs; + iter->second.second = expanded_output; + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Switch allocation failed for VC " << vc + << " at input " << input + << ": Granted to VC " << granted_vc << "." << endl; + } + iter->second.second = STALL_CROSSBAR_CONFLICT; + } + } else if(_spec_sw_allocator) { + expanded_output = _spec_sw_allocator->OutputAssigned(expanded_input); + if(expanded_output >= 0) { + assert((expanded_output % _output_speedup) == (input % _output_speedup)); + if(_spec_mask_by_reqs && + _sw_allocator->OutputHasRequests(expanded_output)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding speculative grant for VC " << vc + << " at input " << input + << "." << (vc % _input_speedup) + << " because output " << (expanded_output / _output_speedup) + << "." << (expanded_output % _output_speedup) + << " has non-speculative requests." << endl; + } + iter->second.second = STALL_CROSSBAR_CONFLICT; + } else if(!_spec_mask_by_reqs && + (_sw_allocator->InputAssigned(expanded_output) >= 0)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding speculative grant for VC " << vc + << " at input " << input + << "." << (vc % _input_speedup) + << " because output " << (expanded_output / _output_speedup) + << "." << (expanded_output % _output_speedup) + << " has a non-speculative grant." << endl; + } + iter->second.second = STALL_CROSSBAR_CONFLICT; + } else { + int const granted_vc = _spec_sw_allocator->ReadRequest(expanded_input, + expanded_output); + if(granted_vc == vc) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Assigning output " << (expanded_output / _output_speedup) + << "." << (expanded_output % _output_speedup) + << " to VC " << vc + << " at input " << input + << "." << (vc % _input_speedup) + << "." << endl; + } + _sw_rr_offset[expanded_input] = (vc + _input_speedup) % _vcs; + iter->second.second = expanded_output; + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Switch allocation failed for VC " << vc + << " at input " << input + << ": Granted to VC " << granted_vc << "." << endl; + } + iter->second.second = STALL_CROSSBAR_CONFLICT; + } + } + } else { + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Switch allocation failed for VC " << vc + << " at input " << input + << ": No output granted." << endl; + } + + iter->second.second = STALL_CROSSBAR_CONFLICT; + + } + } else { + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Switch allocation failed for VC " << vc + << " at input " << input + << ": No output granted." << endl; + } + + iter->second.second = STALL_CROSSBAR_CONFLICT; + + } + } + + if(!_speculative && (_sw_alloc_delay <= 1)) { + return; + } + + for(deque<pair<int, pair<pair<int, int>, int> > >::iterator iter = _sw_alloc_vcs.begin(); + iter != _sw_alloc_vcs.end(); + ++iter) { + + int const time = iter->first; + assert(time >= 0); + if(GetSimTime() < time) { + break; + } + + assert(iter->second.second != -1); + + int const expanded_output = iter->second.second; + + if(expanded_output >= 0) { + + int const output = expanded_output / _output_speedup; + assert((output >= 0) && (output < _outputs)); + + BufferState const * const dest_buf = _next_buf[output]; + + int const input = iter->second.first.first; + assert((input >= 0) && (input < _inputs)); + assert((input % _output_speedup) == (expanded_output % _output_speedup)); + int const vc = iter->second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + int const expanded_input = input * _input_speedup + vc % _input_speedup; + assert(_switch_hold_vc[expanded_input] != vc); + + Buffer const * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert((cur_buf->GetState(vc) == VC::active) || + (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc))); + + Flit const * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + if((_switch_hold_in[expanded_input] >= 0) || + (_switch_hold_out[expanded_output] >= 0)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " due to conflict with held connection at "; + if(_switch_hold_in[expanded_input] >= 0) { + *gWatchOut << "input"; + } + if((_switch_hold_in[expanded_input] >= 0) && + (_switch_hold_out[expanded_output] >= 0)) { + *gWatchOut << " and "; + } + if(_switch_hold_out[expanded_output] >= 0) { + *gWatchOut << "output"; + } + *gWatchOut << "." << endl; + } + iter->second.second = STALL_CROSSBAR_CONFLICT; + } else if(_speculative && (cur_buf->GetState(vc) == VC::vc_alloc)) { + + assert(f->head); + + if(_vc_allocator) { // separate VC and switch allocators + + int const input_and_vc = + _vc_shuffle_requests ? (vc*_inputs + input) : (input*_vcs + vc); + int const output_and_vc = _vc_allocator->OutputAssigned(input_and_vc); + + if(output_and_vc < 0) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " due to misspeculation." << endl; + } + iter->second.second = -1; // stall is counted in VC allocation path! + } else if((output_and_vc / _vcs) != output) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " due to port mismatch between VC and switch allocator." << endl; + } + iter->second.second = STALL_BUFFER_CONFLICT; // count this case as if we had failed allocation + } else if(dest_buf->IsFullFor((output_and_vc % _vcs))) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " due to lack of credit." << endl; + } + iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED; + } + + } else { // VC allocation is piggybacked onto switch allocation + + OutputSet const * const route_set = cur_buf->GetRouteSet(vc); + assert(route_set); + + set<OutputSet::sSetElement> const setlist = route_set->GetSet(); + + bool busy = true; + bool full = true; + bool reserved = false; + + assert(!_noq || (setlist.size() == 1)); + + for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin(); + iset != setlist.end(); + ++iset) { + if(iset->output_port == output) { + + int vc_start; + int vc_end; + + if(_noq && _noq_next_output_port[input][vc] >= 0) { + assert(!_routing_delay); + vc_start = _noq_next_vc_start[input][vc]; + vc_end = _noq_next_vc_end[input][vc]; + } else { + vc_start = iset->vc_start; + vc_end = iset->vc_end; + } + assert(vc_start >= 0 && vc_start < _vcs); + assert(vc_end >= 0 && vc_end < _vcs); + assert(vc_end >= vc_start); + + for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) { + assert((out_vc >= 0) && (out_vc < _vcs)); + if(dest_buf->IsAvailableFor(out_vc)) { + busy = false; + if(!dest_buf->IsFullFor(out_vc)) { + full = false; + break; + } else if(!dest_buf->IsFull()) { + reserved = true; + } + } + } + if(!full) { + break; + } + } + } + + if(busy) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " because no suitable output VC for piggyback allocation is available." << endl; + } + iter->second.second = STALL_BUFFER_BUSY; + } else if(full) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " because all suitable output VCs for piggyback allocation are full." << endl; + } + iter->second.second = reserved ? STALL_BUFFER_RESERVED : STALL_BUFFER_FULL; + } + + } + + } else { + assert(cur_buf->GetOutputPort(vc) == output); + + int const match_vc = cur_buf->GetOutputVC(vc); + assert((match_vc >= 0) && (match_vc < _vcs)); + + if(dest_buf->IsFullFor(match_vc)) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Discarding grant from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << " due to lack of credit." << endl; + } + iter->second.second = dest_buf->IsFull() ? STALL_BUFFER_FULL : STALL_BUFFER_RESERVED; + } + } + } + } +} + +void IQRouter::_SWAllocUpdate( ) +{ + while(!_sw_alloc_vcs.empty()) { + + pair<int, pair<pair<int, int>, int> > const & item = _sw_alloc_vcs.front(); + + int const time = item.first; + if((time < 0) || (GetSimTime() < time)) { + break; + } + assert(GetSimTime() == time); + + int const input = item.second.first.first; + assert((input >= 0) && (input < _inputs)); + int const vc = item.second.first.second; + assert((vc >= 0) && (vc < _vcs)); + + Buffer * const cur_buf = _buf[input]; + assert(!cur_buf->Empty(vc)); + assert((cur_buf->GetState(vc) == VC::active) || + (_speculative && (cur_buf->GetState(vc) == VC::vc_alloc))); + + Flit * const f = cur_buf->FrontFlit(vc); + assert(f); + assert(f->vc == vc); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Completed switch allocation for VC " << vc + << " at input " << input + << " (front: " << f->id + << ")." << endl; + } + + int const expanded_output = item.second.second; + + if(expanded_output >= 0) { + + int const expanded_input = input * _input_speedup + vc % _input_speedup; + assert(_switch_hold_vc[expanded_input] < 0); + assert(_switch_hold_in[expanded_input] < 0); + assert(_switch_hold_out[expanded_output] < 0); + + int const output = expanded_output / _output_speedup; + assert((output >= 0) && (output < _outputs)); + + BufferState * const dest_buf = _next_buf[output]; + + int match_vc; + + if(!_vc_allocator && (cur_buf->GetState(vc) == VC::vc_alloc)) { + + assert(f->head); + + int const cl = f->cl; + assert((cl >= 0) && (cl < _classes)); + + int const vc_offset = _vc_rr_offset[output*_classes+cl]; + + match_vc = -1; + int match_prio = numeric_limits<int>::min(); + + const OutputSet * route_set = cur_buf->GetRouteSet(vc); + set<OutputSet::sSetElement> const setlist = route_set->GetSet(); + + assert(!_noq || (setlist.size() == 1)); + + for(set<OutputSet::sSetElement>::const_iterator iset = setlist.begin(); + iset != setlist.end(); + ++iset) { + if(iset->output_port == output) { + + int vc_start; + int vc_end; + + if(_noq && _noq_next_output_port[input][vc] >= 0) { + assert(!_routing_delay); + vc_start = _noq_next_vc_start[input][vc]; + vc_end = _noq_next_vc_end[input][vc]; + } else { + vc_start = iset->vc_start; + vc_end = iset->vc_end; + } + assert(vc_start >= 0 && vc_start < _vcs); + assert(vc_end >= 0 && vc_end < _vcs); + assert(vc_end >= vc_start); + + for(int out_vc = vc_start; out_vc <= vc_end; ++out_vc) { + assert((out_vc >= 0) && (out_vc < _vcs)); + + int vc_prio = iset->pri; + if(_vc_prioritize_empty && !dest_buf->IsEmptyFor(out_vc)) { + assert(vc_prio >= 0); + vc_prio += numeric_limits<int>::min(); + } + + // FIXME: This check should probably be performed in Evaluate(), + // not Update(), as the latter can cause the outcome to depend on + // the order of evaluation! + if(dest_buf->IsAvailableFor(out_vc) && + !dest_buf->IsFullFor(out_vc) && + ((match_vc < 0) || + RoundRobinArbiter::Supersedes(out_vc, vc_prio, + match_vc, match_prio, + vc_offset, _vcs))) { + match_vc = out_vc; + match_prio = vc_prio; + } + } + } + } + assert(match_vc >= 0); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Allocating VC " << match_vc + << " at output " << output + << " via piggyback VC allocation." << endl; + } + + cur_buf->SetState(vc, VC::active); + cur_buf->SetOutput(vc, output, match_vc); + dest_buf->TakeBuffer(match_vc, input*_vcs + vc); + + _vc_rr_offset[output*_classes+cl] = (match_vc + 1) % _vcs; + + } else { + + assert(cur_buf->GetOutputPort(vc) == output); + + match_vc = cur_buf->GetOutputVC(vc); + + } + assert((match_vc >= 0) && (match_vc < _vcs)); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Scheduling switch connection from input " << input + << "." << (vc % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << "." << endl; + } + + cur_buf->RemoveFlit(vc); + +#ifdef TRACK_FLOWS + --_stored_flits[f->cl][input]; + if(f->tail) --_active_packets[f->cl][input]; +#endif + + _bufferMonitor->read(input, f) ; + + f->hops++; + f->vc = match_vc; + + if(!_routing_delay && f->head) { + const FlitChannel * channel = _output_channels[output]; + const Router * router = channel->GetSink(); + if(router) { + if(_noq) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Updating lookahead routing information for flit " << f->id + << " (NOQ)." << endl; + } + int next_output_port = _noq_next_output_port[input][vc]; + assert(next_output_port >= 0); + _noq_next_output_port[input][vc] = -1; + int next_vc_start = _noq_next_vc_start[input][vc]; + assert(next_vc_start >= 0 && next_vc_start < _vcs); + _noq_next_vc_start[input][vc] = -1; + int next_vc_end = _noq_next_vc_end[input][vc]; + assert(next_vc_end >= 0 && next_vc_end < _vcs); + _noq_next_vc_end[input][vc] = -1; + f->la_route_set.Clear(); + f->la_route_set.AddRange(next_output_port, next_vc_start, next_vc_end); + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Updating lookahead routing information for flit " << f->id + << "." << endl; + } + int in_channel = channel->GetSinkPort(); + _rf(router, f, in_channel, &f->la_route_set, false); + } + } else { + f->la_route_set.Clear(); + } + } + +#ifdef TRACK_FLOWS + ++_outstanding_credits[f->cl][output]; + _outstanding_classes[output][f->vc].push(f->cl); +#endif + + dest_buf->SendingFlit(f); + + _crossbar_flits.push_back(make_pair(-1, make_pair(f, make_pair(expanded_input, expanded_output)))); + + if(_out_queue_credits.count(input) == 0) { + _out_queue_credits.insert(make_pair(input, Credit::New())); + } + _out_queue_credits.find(input)->second->vc.insert(vc); + + if(cur_buf->Empty(vc)) { + if(f->tail) { + cur_buf->SetState(vc, VC::idle); + } + } else { + Flit * const nf = cur_buf->FrontFlit(vc); + assert(nf); + assert(nf->vc == vc); + if(f->tail) { + assert(nf->head); + if(_routing_delay) { + cur_buf->SetState(vc, VC::routing); + _route_vcs.push_back(make_pair(-1, item.second.first)); + } else { + if(nf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Using precomputed lookahead routing information for VC " << vc + << " at input " << input + << " (front: " << nf->id + << ")." << endl; + } + cur_buf->SetRouteSet(vc, &nf->la_route_set); + cur_buf->SetState(vc, VC::vc_alloc); + if(_speculative) { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + if(_vc_allocator) { + _vc_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + if(_noq) { + _UpdateNOQ(input, vc, nf); + } + } + } else { + if(_hold_switch_for_packet) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Setting up switch hold for VC " << vc + << " at input " << input + << "." << (expanded_input % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << "." << endl; + } + _switch_hold_vc[expanded_input] = vc; + _switch_hold_in[expanded_input] = expanded_output; + _switch_hold_out[expanded_output] = expanded_input; + _sw_hold_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } else { + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, + -1))); + } + } + } + } else { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " No output port allocated." << endl; + } + +#ifdef TRACK_STALLS + assert((expanded_output == -1) || // for stalls that are accounted for in VC allocation path + (expanded_output == STALL_BUFFER_BUSY) || + (expanded_output == STALL_BUFFER_CONFLICT) || + (expanded_output == STALL_BUFFER_FULL) || + (expanded_output == STALL_BUFFER_RESERVED) || + (expanded_output == STALL_CROSSBAR_CONFLICT)); + if(expanded_output == STALL_BUFFER_BUSY) { + ++_buffer_busy_stalls[f->cl]; + } else if(expanded_output == STALL_BUFFER_CONFLICT) { + ++_buffer_conflict_stalls[f->cl]; + } else if(expanded_output == STALL_BUFFER_FULL) { + ++_buffer_full_stalls[f->cl]; + } else if(expanded_output == STALL_BUFFER_RESERVED) { + ++_buffer_reserved_stalls[f->cl]; + } else if(expanded_output == STALL_CROSSBAR_CONFLICT) { + ++_crossbar_conflict_stalls[f->cl]; + } +#endif + + _sw_alloc_vcs.push_back(make_pair(-1, make_pair(item.second.first, -1))); + } + _sw_alloc_vcs.pop_front(); + } +} + + +//------------------------------------------------------------------------------ +// switch traversal +//------------------------------------------------------------------------------ + +void IQRouter::_SwitchEvaluate( ) +{ + for(deque<pair<int, pair<Flit *, pair<int, int> > > >::iterator iter = _crossbar_flits.begin(); + iter != _crossbar_flits.end(); + ++iter) { + + int const time = iter->first; + if(time >= 0) { + break; + } + iter->first = GetSimTime() + _crossbar_delay - 1; + + Flit const * const f = iter->second.first; + assert(f); + + int const expanded_input = iter->second.second.first; + int const expanded_output = iter->second.second.second; + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Beginning crossbar traversal for flit " << f->id + << " from input " << (expanded_input / _input_speedup) + << "." << (expanded_input % _input_speedup) + << " to output " << (expanded_output / _output_speedup) + << "." << (expanded_output % _output_speedup) + << "." << endl; + } + } +} + +void IQRouter::_SwitchUpdate( ) +{ + while(!_crossbar_flits.empty()) { + + pair<int, pair<Flit *, pair<int, int> > > const & item = _crossbar_flits.front(); + + int const time = item.first; + if((time < 0) || (GetSimTime() < time)) { + break; + } + assert(GetSimTime() == time); + + Flit * const f = item.second.first; + assert(f); + + int const expanded_input = item.second.second.first; + int const input = expanded_input / _input_speedup; + assert((input >= 0) && (input < _inputs)); + int const expanded_output = item.second.second.second; + int const output = expanded_output / _output_speedup; + assert((output >= 0) && (output < _outputs)); + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Completed crossbar traversal for flit " << f->id + << " from input " << input + << "." << (expanded_input % _input_speedup) + << " to output " << output + << "." << (expanded_output % _output_speedup) + << "." << endl; + } + _switchMonitor->traversal(input, output, f) ; + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Buffering flit " << f->id + << " at output " << output + << "." << endl; + } + _output_buffer[output].push(f); + //the output buffer size isn't precise due to flits in flight + //but there is a maximum bound based on output speed up and ST traversal + assert(_output_buffer[output].size()<=(size_t)_output_buffer_size+ _crossbar_delay* _output_speedup+( _output_speedup-1) ||_output_buffer_size==-1); + _crossbar_flits.pop_front(); + } +} + + +//------------------------------------------------------------------------------ +// output queuing +//------------------------------------------------------------------------------ + +void IQRouter::_OutputQueuing( ) +{ + for(map<int, Credit *>::const_iterator iter = _out_queue_credits.begin(); + iter != _out_queue_credits.end(); + ++iter) { + + int const input = iter->first; + assert((input >= 0) && (input < _inputs)); + + Credit * const c = iter->second; + assert(c); + assert(!c->vc.empty()); + + _credit_buffer[input].push(c); + } + _out_queue_credits.clear(); +} + +//------------------------------------------------------------------------------ +// write outputs +//------------------------------------------------------------------------------ + +void IQRouter::_SendFlits( ) +{ + for ( int output = 0; output < _outputs; ++output ) { + if ( !_output_buffer[output].empty( ) ) { + Flit * const f = _output_buffer[output].front( ); + assert(f); + _output_buffer[output].pop( ); + +#ifdef TRACK_FLOWS + ++_sent_flits[f->cl][output]; +#endif + + if(f->watch) + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Sending flit " << f->id + << " to channel at output " << output + << "." << endl; + if(gTrace) { + cout << "Outport " << output << endl << "Stop Mark" << endl; + } + _output_channels[output]->Send( f ); + } + } +} + +void IQRouter::_SendCredits( ) +{ + for ( int input = 0; input < _inputs; ++input ) { + if ( !_credit_buffer[input].empty( ) ) { + Credit * const c = _credit_buffer[input].front( ); + assert(c); + _credit_buffer[input].pop( ); + _input_credits[input]->Send( c ); + } + } +} + + +//------------------------------------------------------------------------------ +// misc. +//------------------------------------------------------------------------------ + +void IQRouter::Display( ostream & os ) const +{ + for ( int input = 0; input < _inputs; ++input ) { + _buf[input]->Display( os ); + } +} + +int IQRouter::GetUsedCredit(int o) const +{ + assert((o >= 0) && (o < _outputs)); + BufferState const * const dest_buf = _next_buf[o]; + return dest_buf->Occupancy(); +} + +int IQRouter::GetBufferOccupancy(int i) const { + assert(i >= 0 && i < _inputs); + return _buf[i]->GetOccupancy(); +} + +#ifdef TRACK_BUFFERS +int IQRouter::GetUsedCreditForClass(int output, int cl) const +{ + assert((output >= 0) && (output < _outputs)); + BufferState const * const dest_buf = _next_buf[output]; + return dest_buf->OccupancyForClass(cl); +} + +int IQRouter::GetBufferOccupancyForClass(int input, int cl) const +{ + assert((input >= 0) && (input < _inputs)); + return _buf[input]->GetOccupancyForClass(cl); +} +#endif + +vector<int> IQRouter::UsedCredits() const +{ + vector<int> result(_outputs*_vcs); + for(int o = 0; o < _outputs; ++o) { + for(int v = 0; v < _vcs; ++v) { + result[o*_vcs+v] = _next_buf[o]->OccupancyFor(v); + } + } + return result; +} + +vector<int> IQRouter::FreeCredits() const +{ + vector<int> result(_outputs*_vcs); + for(int o = 0; o < _outputs; ++o) { + for(int v = 0; v < _vcs; ++v) { + result[o*_vcs+v] = _next_buf[o]->AvailableFor(v); + } + } + return result; +} + +vector<int> IQRouter::MaxCredits() const +{ + vector<int> result(_outputs*_vcs); + for(int o = 0; o < _outputs; ++o) { + for(int v = 0; v < _vcs; ++v) { + result[o*_vcs+v] = _next_buf[o]->LimitFor(v); + } + } + return result; +} + +void IQRouter::_UpdateNOQ(int input, int vc, Flit const * f) { + assert(!_routing_delay); + assert(f); + assert(f->vc == vc); + assert(f->head); + set<OutputSet::sSetElement> sl = f->la_route_set.GetSet(); + assert(sl.size() == 1); + int out_port = sl.begin()->output_port; + const FlitChannel * channel = _output_channels[out_port]; + const Router * router = channel->GetSink(); + if(router) { + int in_channel = channel->GetSinkPort(); + OutputSet nos; + _rf(router, f, in_channel, &nos, false); + sl = nos.GetSet(); + assert(sl.size() == 1); + OutputSet::sSetElement const & se = *sl.begin(); + int next_output_port = se.output_port; + assert(next_output_port >= 0); + assert(_noq_next_output_port[input][vc] < 0); + _noq_next_output_port[input][vc] = next_output_port; + int next_vc_count = (se.vc_end - se.vc_start + 1) / router->NumOutputs(); + int next_vc_start = se.vc_start + next_output_port * next_vc_count; + assert(next_vc_start >= 0 && next_vc_start < _vcs); + assert(_noq_next_vc_start[input][vc] < 0); + _noq_next_vc_start[input][vc] = next_vc_start; + int next_vc_end = se.vc_start + (next_output_port + 1) * next_vc_count - 1; + assert(next_vc_end >= 0 && next_vc_end < _vcs); + assert(_noq_next_vc_end[input][vc] < 0); + _noq_next_vc_end[input][vc] = next_vc_end; + assert(next_vc_start <= next_vc_end); + if(f->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Computing lookahead routing information for flit " << f->id + << " (NOQ)." << endl; + } + } +} diff --git a/src/intersim2/routers/iq_router.hpp b/src/intersim2/routers/iq_router.hpp new file mode 100644 index 0000000..b64502d --- /dev/null +++ b/src/intersim2/routers/iq_router.hpp @@ -0,0 +1,183 @@ +// $Id: iq_router.hpp 5263 2012-09-20 23:40:33Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _IQ_ROUTER_HPP_ +#define _IQ_ROUTER_HPP_ + +#include <string> +#include <deque> +#include <queue> +#include <set> +#include <map> + +#include "router.hpp" +#include "routefunc.hpp" + +using namespace std; + +class VC; +class Flit; +class Credit; +class Buffer; +class BufferState; +class Allocator; +class SwitchMonitor; +class BufferMonitor; + +class IQRouter : public Router { + + int _vcs; + + bool _vc_busy_when_full; + bool _vc_prioritize_empty; + bool _vc_shuffle_requests; + + bool _speculative; + bool _spec_check_elig; + bool _spec_check_cred; + bool _spec_mask_by_reqs; + + bool _active; + + int _routing_delay; + int _vc_alloc_delay; + int _sw_alloc_delay; + + map<int, Flit *> _in_queue_flits; + + deque<pair<int, pair<Credit *, int> > > _proc_credits; + + deque<pair<int, pair<int, int> > > _route_vcs; + deque<pair<int, pair<pair<int, int>, int> > > _vc_alloc_vcs; + deque<pair<int, pair<pair<int, int>, int> > > _sw_hold_vcs; + deque<pair<int, pair<pair<int, int>, int> > > _sw_alloc_vcs; + + deque<pair<int, pair<Flit *, pair<int, int> > > > _crossbar_flits; + + map<int, Credit *> _out_queue_credits; + + vector<Buffer *> _buf; + vector<BufferState *> _next_buf; + + Allocator *_vc_allocator; + Allocator *_sw_allocator; + Allocator *_spec_sw_allocator; + + vector<int> _vc_rr_offset; + vector<int> _sw_rr_offset; + + tRoutingFunction _rf; + + int _output_buffer_size; + vector<queue<Flit *> > _output_buffer; + + vector<queue<Credit *> > _credit_buffer; + + bool _hold_switch_for_packet; + vector<int> _switch_hold_in; + vector<int> _switch_hold_out; + vector<int> _switch_hold_vc; + + bool _noq; + vector<vector<int> > _noq_next_output_port; + vector<vector<int> > _noq_next_vc_start; + vector<vector<int> > _noq_next_vc_end; + +#ifdef TRACK_FLOWS + vector<vector<queue<int> > > _outstanding_classes; +#endif + + bool _ReceiveFlits( ); + bool _ReceiveCredits( ); + + virtual void _InternalStep( ); + + bool _SWAllocAddReq(int input, int vc, int output); + + void _InputQueuing( ); + + void _RouteEvaluate( ); + void _VCAllocEvaluate( ); + void _SWHoldEvaluate( ); + void _SWAllocEvaluate( ); + void _SwitchEvaluate( ); + + void _RouteUpdate( ); + void _VCAllocUpdate( ); + void _SWHoldUpdate( ); + void _SWAllocUpdate( ); + void _SwitchUpdate( ); + + void _OutputQueuing( ); + + void _SendFlits( ); + void _SendCredits( ); + + void _UpdateNOQ(int input, int vc, Flit const * f); + + // ---------------------------------------- + // + // Router Power Modellingyes + // + // ---------------------------------------- + + SwitchMonitor * _switchMonitor ; + BufferMonitor * _bufferMonitor ; + +public: + + IQRouter( Configuration const & config, + Module *parent, string const & name, int id, + int inputs, int outputs ); + + virtual ~IQRouter( ); + + virtual void AddOutputChannel(FlitChannel * channel, CreditChannel * backchannel); + + virtual void ReadInputs( ); + virtual void WriteOutputs( ); + + void Display( ostream & os = cout ) const; + + virtual int GetUsedCredit(int o) const; + virtual int GetBufferOccupancy(int i) const; + +#ifdef TRACK_BUFFERS + virtual int GetUsedCreditForClass(int output, int cl) const; + virtual int GetBufferOccupancyForClass(int input, int cl) const; +#endif + + virtual vector<int> UsedCredits() const; + virtual vector<int> FreeCredits() const; + virtual vector<int> MaxCredits() const; + + SwitchMonitor const * const GetSwitchMonitor() const {return _switchMonitor;} + BufferMonitor const * const GetBufferMonitor() const {return _bufferMonitor;} + +}; + +#endif diff --git a/src/intersim2/routers/router.cpp b/src/intersim2/routers/router.cpp new file mode 100644 index 0000000..cb6f078 --- /dev/null +++ b/src/intersim2/routers/router.cpp @@ -0,0 +1,155 @@ +// $Id: router.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*router.cpp + * + *The base class of either iq router or event router + *contains a list of channels and other router configuration variables + * + *The older version of the simulator uses an array of flits and credit to + *simulate the channels. Newer version ueses flitchannel and credit channel + *which can better model channel delay + * + *The older version of the simulator also uses vc_router and chaos router + *which are replaced by iq rotuer and event router in the present form + */ + +#include "booksim.hpp" +#include <iostream> +#include <cassert> +#include "router.hpp" + +//////////////////Sub router types////////////////////// +#include "iq_router.hpp" +#include "event_router.hpp" +#include "chaos_router.hpp" +/////////////////////////////////////////////////////// + +int const Router::STALL_BUFFER_BUSY = -2; +int const Router::STALL_BUFFER_CONFLICT = -3; +int const Router::STALL_BUFFER_FULL = -4; +int const Router::STALL_BUFFER_RESERVED = -5; +int const Router::STALL_CROSSBAR_CONFLICT = -6; + +Router::Router( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ) : +TimedModule( parent, name ), _id( id ), _inputs( inputs ), _outputs( outputs ), + _partial_internal_cycles(0.0) +{ + _crossbar_delay = ( config.GetInt( "st_prepare_delay" ) + + config.GetInt( "st_final_delay" ) ); + _credit_delay = config.GetInt( "credit_delay" ); + _input_speedup = config.GetInt( "input_speedup" ); + _output_speedup = config.GetInt( "output_speedup" ); + _internal_speedup = config.GetFloat( "internal_speedup" ); + _classes = config.GetInt( "classes" ); + +#ifdef TRACK_FLOWS + _received_flits.resize(_classes, vector<int>(_inputs, 0)); + _stored_flits.resize(_classes); + _sent_flits.resize(_classes, vector<int>(_outputs, 0)); + _active_packets.resize(_classes); + _outstanding_credits.resize(_classes, vector<int>(_outputs, 0)); +#endif + +#ifdef TRACK_STALLS + _buffer_busy_stalls.resize(_classes, 0); + _buffer_conflict_stalls.resize(_classes, 0); + _buffer_full_stalls.resize(_classes, 0); + _buffer_reserved_stalls.resize(_classes, 0); + _crossbar_conflict_stalls.resize(_classes, 0); +#endif + +} + +void Router::AddInputChannel( FlitChannel *channel, CreditChannel *backchannel ) +{ + _input_channels.push_back( channel ); + _input_credits.push_back( backchannel ); + channel->SetSink( this, _input_channels.size() - 1 ) ; +} + +void Router::AddOutputChannel( FlitChannel *channel, CreditChannel *backchannel ) +{ + _output_channels.push_back( channel ); + _output_credits.push_back( backchannel ); + _channel_faults.push_back( false ); + channel->SetSource( this, _output_channels.size() - 1 ) ; +} + +void Router::Evaluate( ) +{ + _partial_internal_cycles += _internal_speedup; + while( _partial_internal_cycles >= 1.0 ) { + _InternalStep( ); + _partial_internal_cycles -= 1.0; + } +} + +void Router::OutChannelFault( int c, bool fault ) +{ + assert( ( c >= 0 ) && ( (size_t)c < _channel_faults.size( ) ) ); + + _channel_faults[c] = fault; +} + +bool Router::IsFaultyOutput( int c ) const +{ + assert( ( c >= 0 ) && ( (size_t)c < _channel_faults.size( ) ) ); + + return _channel_faults[c]; +} + +/*Router constructor*/ +Router *Router::NewRouter( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ) +{ + const string type = config.GetStr( "router" ); + Router *r = NULL; + if ( type == "iq" ) { + r = new IQRouter( config, parent, name, id, inputs, outputs ); + } else if ( type == "event" ) { + r = new EventRouter( config, parent, name, id, inputs, outputs ); + } else if ( type == "chaos" ) { + r = new ChaosRouter( config, parent, name, id, inputs, outputs ); + } else { + cerr << "Unknown router type: " << type << endl; + } + /*For additional router, add another else if statement*/ + /*Original booksim specifies the router using "flow_control" + *we now simply call these types. + */ + + return r; +} + + + + + diff --git a/src/intersim2/routers/router.hpp b/src/intersim2/routers/router.hpp new file mode 100644 index 0000000..1dff57f --- /dev/null +++ b/src/intersim2/routers/router.hpp @@ -0,0 +1,202 @@ +// $Id: router.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _ROUTER_HPP_ +#define _ROUTER_HPP_ + +#include <string> +#include <vector> + +#include "timed_module.hpp" +#include "flit.hpp" +#include "credit.hpp" +#include "flitchannel.hpp" +#include "channel.hpp" +#include "config_utils.hpp" + +typedef Channel<Credit> CreditChannel; + +class Router : public TimedModule { + +protected: + + static int const STALL_BUFFER_BUSY; + static int const STALL_BUFFER_CONFLICT; + static int const STALL_BUFFER_FULL; + static int const STALL_BUFFER_RESERVED; + static int const STALL_CROSSBAR_CONFLICT; + + int _id; + + int _inputs; + int _outputs; + + int _classes; + + int _input_speedup; + int _output_speedup; + + double _internal_speedup; + double _partial_internal_cycles; + + int _crossbar_delay; + int _credit_delay; + + vector<FlitChannel *> _input_channels; + vector<CreditChannel *> _input_credits; + vector<FlitChannel *> _output_channels; + vector<CreditChannel *> _output_credits; + vector<bool> _channel_faults; + +#ifdef TRACK_FLOWS + vector<vector<int> > _received_flits; + vector<vector<int> > _stored_flits; + vector<vector<int> > _sent_flits; + vector<vector<int> > _outstanding_credits; + vector<vector<int> > _active_packets; +#endif + +#ifdef TRACK_STALLS + vector<int> _buffer_busy_stalls; + vector<int> _buffer_conflict_stalls; + vector<int> _buffer_full_stalls; + vector<int> _buffer_reserved_stalls; + vector<int> _crossbar_conflict_stalls; +#endif + + virtual void _InternalStep() = 0; + +public: + Router( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ); + + static Router *NewRouter( const Configuration& config, + Module *parent, const string & name, int id, + int inputs, int outputs ); + + virtual void AddInputChannel( FlitChannel *channel, CreditChannel *backchannel ); + virtual void AddOutputChannel( FlitChannel *channel, CreditChannel *backchannel ); + + inline FlitChannel * GetInputChannel( int input ) const { + assert((input >= 0) && (input < _inputs)); + return _input_channels[input]; + } + inline FlitChannel * GetOutputChannel( int output ) const { + assert((output >= 0) && (output < _outputs)); + return _output_channels[output]; + } + + virtual void ReadInputs( ) = 0; + virtual void Evaluate( ); + virtual void WriteOutputs( ) = 0; + + void OutChannelFault( int c, bool fault = true ); + bool IsFaultyOutput( int c ) const; + + inline int GetID( ) const {return _id;} + + + virtual int GetUsedCredit(int o) const = 0; + virtual int GetBufferOccupancy(int i) const = 0; + +#ifdef TRACK_BUFFERS + virtual int GetUsedCreditForClass(int output, int cl) const = 0; + virtual int GetBufferOccupancyForClass(int input, int cl) const = 0; +#endif + +#ifdef TRACK_FLOWS + inline vector<int> const & GetReceivedFlits(int c) const { + assert((c >= 0) && (c < _classes)); + return _received_flits[c]; + } + inline vector<int> const & GetStoredFlits(int c) const { + assert((c >= 0) && (c < _classes)); + return _stored_flits[c]; + } + inline vector<int> const & GetSentFlits(int c) const { + assert((c >= 0) && (c < _classes)); + return _sent_flits[c]; + } + inline vector<int> const & GetOutstandingCredits(int c) const { + assert((c >= 0) && (c < _classes)); + return _outstanding_credits[c]; + } + + inline vector<int> const & GetActivePackets(int c) const { + assert((c >= 0) && (c < _classes)); + return _active_packets[c]; + } + + inline void ResetFlowStats(int c) { + assert((c >= 0) && (c < _classes)); + _received_flits[c].assign(_received_flits[c].size(), 0); + _sent_flits[c].assign(_sent_flits[c].size(), 0); + } +#endif + + virtual vector<int> UsedCredits() const = 0; + virtual vector<int> FreeCredits() const = 0; + virtual vector<int> MaxCredits() const = 0; + +#ifdef TRACK_STALLS + inline int GetBufferBusyStalls(int c) const { + assert((c >= 0) && (c < _classes)); + return _buffer_busy_stalls[c]; + } + inline int GetBufferConflictStalls(int c) const { + assert((c >= 0) && (c < _classes)); + return _buffer_conflict_stalls[c]; + } + inline int GetBufferFullStalls(int c) const { + assert((c >= 0) && (c < _classes)); + return _buffer_full_stalls[c]; + } + inline int GetBufferReservedStalls(int c) const { + assert((c >= 0) && (c < _classes)); + return _buffer_reserved_stalls[c]; + } + inline int GetCrossbarConflictStalls(int c) const { + assert((c >= 0) && (c < _classes)); + return _crossbar_conflict_stalls[c]; + } + + inline void ResetStallStats(int c) { + assert((c >= 0) && (c < _classes)); + _buffer_busy_stalls[c] = 0; + _buffer_conflict_stalls[c] = 0; + _buffer_full_stalls[c] = 0; + _buffer_reserved_stalls[c] = 0; + _crossbar_conflict_stalls[c] = 0; + } +#endif + + inline int NumInputs() const {return _inputs;} + inline int NumOutputs() const {return _outputs;} +}; + +#endif diff --git a/src/intersim2/stats.cpp b/src/intersim2/stats.cpp new file mode 100644 index 0000000..b585b35 --- /dev/null +++ b/src/intersim2/stats.cpp @@ -0,0 +1,130 @@ +// $Id: stats.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*stats.cpp + * + *class stores statistics gnerated by the trafficmanager such as the latency + *hope count of the the flits + * + *reset option resets the min and max alues of this statistiscs + */ + +#include "booksim.hpp" +#include <iostream> +#include <sstream> +#include <limits> +#include <cmath> +#include <cstdio> + +#include "stats.hpp" + +Stats::Stats( Module *parent, const string &name, + double bin_size, int num_bins ) : + Module( parent, name ), _num_bins( num_bins ), _bin_size( bin_size ) +{ + Clear(); +} + +void Stats::Clear( ) +{ + _num_samples = 0; + _sample_sum = 0.0; + _sample_squared_sum = 0.0; + + _hist.assign(_num_bins, 0); + + _min = numeric_limits<double>::quiet_NaN(); + _max = -numeric_limits<double>::quiet_NaN(); + + // _reset = true; +} + +double Stats::Average( ) const +{ + return _sample_sum / (double)_num_samples; +} + +double Stats::Variance( ) const +{ + return (_sample_squared_sum * (double)_num_samples - _sample_sum * _sample_sum) / ((double)_num_samples * (double)_num_samples); +} + +double Stats::Min( ) const +{ + return _min; +} + +double Stats::Max( ) const +{ + return _max; +} + +double Stats::Sum( ) const +{ + return _sample_sum; +} + +double Stats::SquaredSum( ) const +{ + return _sample_squared_sum; +} + +int Stats::NumSamples( ) const +{ + return _num_samples; +} + +void Stats::AddSample( double val ) +{ + ++_num_samples; + _sample_sum += val; + + // NOTE: the negation ensures that NaN values are handled correctly! + _max = !(val <= _max) ? val : _max; + _min = !(val >= _min) ? val : _min; + + //double clamp between 0 and num_bins-1 + int b = (int)fmax(floor( val / _bin_size ), 0.0); + b = (b >= _num_bins) ? (_num_bins - 1) : b; + + _hist[b]++; +} + +void Stats::Display( ostream & os ) const +{ + os << *this << endl; +} + +ostream & operator<<(ostream & os, const Stats & s) { + vector<int> const & v = s._hist; + os << "[ "; + for(size_t i = 0; i < v.size(); ++i) { + os << v[i] << " "; + } + os << "]"; + return os; +} diff --git a/src/intersim2/stats.hpp b/src/intersim2/stats.hpp new file mode 100644 index 0000000..1aaf013 --- /dev/null +++ b/src/intersim2/stats.hpp @@ -0,0 +1,76 @@ +// $Id: stats.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _STATS_HPP_ +#define _STATS_HPP_ + +#include "module.hpp" + +class Stats : public Module { + int _num_samples; + double _sample_sum; + double _sample_squared_sum; + + //bool _reset; + double _min; + double _max; + + int _num_bins; + double _bin_size; + + vector<int> _hist; + +public: + Stats( Module *parent, const string &name, + double bin_size = 1.0, int num_bins = 10 ); + + void Clear( ); + + double Average( ) const; + double Variance( ) const; + double Max( ) const; + double Min( ) const; + double Sum( ) const; + double SquaredSum( ) const; + int NumSamples( ) const; + + void AddSample( double val ); + inline void AddSample( int val ) { + AddSample( (double)val ); + } + + int GetBin(int b){ return _hist[b];} + + void Display( ostream & os = cout ) const; + + friend ostream & operator<<(ostream & os, const Stats & s); + +}; + +ostream & operator<<(ostream & os, const Stats & s); + +#endif diff --git a/src/intersim2/timed_module.hpp b/src/intersim2/timed_module.hpp new file mode 100644 index 0000000..be0edc1 --- /dev/null +++ b/src/intersim2/timed_module.hpp @@ -0,0 +1,44 @@ +// $Id: timed_module.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _TIMED_MODULE_HPP_ +#define _TIMED_MODULE_HPP_ + +#include "module.hpp" + +class TimedModule : public Module { + +public: + TimedModule(Module * parent, string const & name) : Module(parent, name) {} + virtual ~TimedModule() {} + + virtual void ReadInputs() = 0; + virtual void Evaluate() = 0; + virtual void WriteOutputs() = 0; +}; + +#endif diff --git a/src/intersim2/traffic.cpp b/src/intersim2/traffic.cpp new file mode 100644 index 0000000..7ee74a5 --- /dev/null +++ b/src/intersim2/traffic.cpp @@ -0,0 +1,518 @@ +// $Id: traffic.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include <iostream> +#include <sstream> +#include "random_utils.hpp" +#include "traffic.hpp" + +TrafficPattern::TrafficPattern(int nodes) +: _nodes(nodes) +{ + if(nodes <= 0) { + cout << "Error: Traffic patterns require at least one node." << endl; + exit(-1); + } +} + +void TrafficPattern::reset() +{ + +} + +TrafficPattern * TrafficPattern::New(string const & pattern, int nodes, + Configuration const * const config) +{ + string pattern_name; + string param_str; + size_t left = pattern.find_first_of('('); + if(left == string::npos) { + pattern_name = pattern; + } else { + pattern_name = pattern.substr(0, left); + size_t right = pattern.find_last_of(')'); + if(right == string::npos) { + param_str = pattern.substr(left+1); + } else { + param_str = pattern.substr(left+1, right-left-1); + } + } + vector<string> params = tokenize_str(param_str); + + TrafficPattern * result = NULL; + if(pattern_name == "bitcomp") { + result = new BitCompTrafficPattern(nodes); + } else if(pattern_name == "transpose") { + result = new TransposeTrafficPattern(nodes); + } else if(pattern_name == "bitrev") { + result = new BitRevTrafficPattern(nodes); + } else if(pattern_name == "shuffle") { + result = new ShuffleTrafficPattern(nodes); + } else if(pattern_name == "randperm") { + int perm_seed = -1; + if(params.empty()) { + if(config) { + perm_seed = config->GetInt("perm_seed"); + } else { + cout << "Error: Missing parameter for random permutation traffic pattern: " << pattern << endl; + exit(-1); + } + } else { + perm_seed = atoi(params[0].c_str()); + } + result = new RandomPermutationTrafficPattern(nodes, perm_seed); + } else if(pattern_name == "uniform") { + result = new UniformRandomTrafficPattern(nodes); + } else if(pattern_name == "background") { + vector<int> excludes = tokenize_int(params[0]); + result = new UniformBackgroundTrafficPattern(nodes, excludes); + } else if(pattern_name == "diagonal") { + result = new DiagonalTrafficPattern(nodes); + } else if(pattern_name == "asymmetric") { + result = new AsymmetricTrafficPattern(nodes); + } else if(pattern_name == "taper64") { + result = new Taper64TrafficPattern(nodes); + } else if(pattern_name == "bad_dragon") { + bool missing_params = false; + int k = -1; + if(params.size() < 1) { + if(config) { + k = config->GetInt("k"); + } else { + missing_params = true; + } + } else { + k = atoi(params[0].c_str()); + } + int n = -1; + if(params.size() < 2) { + if(config) { + n = config->GetInt("n"); + } else { + missing_params = true; + } + } else { + n = atoi(params[1].c_str()); + } + if(missing_params) { + cout << "Error: Missing parameters for dragonfly bad permutation traffic pattern: " << pattern << endl; + exit(-1); + } + result = new BadPermDFlyTrafficPattern(nodes, k, n); + } else if((pattern_name == "tornado") || (pattern_name == "neighbor") || + (pattern_name == "badperm_yarc")) { + bool missing_params = false; + int k = -1; + if(params.size() < 1) { + if(config) { + k = config->GetInt("k"); + } else { + missing_params = true; + } + } else { + k = atoi(params[0].c_str()); + } + int n = -1; + if(params.size() < 2) { + if(config) { + n = config->GetInt("n"); + } else { + missing_params = true; + } + } else { + n = atoi(params[1].c_str()); + } + int xr = -1; + if(params.size() < 3) { + if(config) { + xr = config->GetInt("xr"); + } else { + missing_params = true; + } + } else { + xr = atoi(params[2].c_str()); + } + if(missing_params) { + cout << "Error: Missing parameters for digit permutation traffic pattern: " << pattern << endl; + exit(-1); + } + if(pattern_name == "tornado") { + result = new TornadoTrafficPattern(nodes, k, n, xr); + } else if(pattern_name == "neighbor") { + result = new NeighborTrafficPattern(nodes, k, n, xr); + } else if(pattern_name == "badperm_yarc") { + result = new BadPermYarcTrafficPattern(nodes, k, n, xr); + } + } else if(pattern_name == "hotspot") { + if(params.empty()) { + params.push_back("-1"); + } + vector<int> hotspots = tokenize_int(params[0]); + for(size_t i = 0; i < hotspots.size(); ++i) { + if(hotspots[i] < 0) { + hotspots[i] = RandomInt(nodes - 1); + } + } + vector<int> rates; + if(params.size() >= 2) { + rates = tokenize_int(params[1]); + rates.resize(hotspots.size(), rates.back()); + } else { + rates.resize(hotspots.size(), 1); + } + result = new HotSpotTrafficPattern(nodes, hotspots, rates); + } else { + cout << "Error: Unknown traffic pattern: " << pattern << endl; + exit(-1); + } + return result; +} + +PermutationTrafficPattern::PermutationTrafficPattern(int nodes) + : TrafficPattern(nodes) +{ + +} + +BitPermutationTrafficPattern::BitPermutationTrafficPattern(int nodes) + : PermutationTrafficPattern(nodes) +{ + if((nodes & -nodes) != nodes) { + cout << "Error: Bit permutation traffic patterns require the number of " + << "nodes to be a power of two." << endl; + exit(-1); + } +} + +BitCompTrafficPattern::BitCompTrafficPattern(int nodes) + : BitPermutationTrafficPattern(nodes) +{ + +} + +int BitCompTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + int const mask = _nodes - 1; + return ~source & mask; +} + +TransposeTrafficPattern::TransposeTrafficPattern(int nodes) + : BitPermutationTrafficPattern(nodes), _shift(0) +{ + while(nodes >>= 1) { + ++_shift; + } + if(_shift % 2) { + cout << "Error: Transpose traffic pattern requires the number of nodes to " + << "be an even power of two." << endl; + exit(-1); + } + _shift >>= 1; +} + +int TransposeTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + int const mask_lo = (1 << _shift) - 1; + int const mask_hi = mask_lo << _shift; + return (((source >> _shift) & mask_lo) | ((source << _shift) & mask_hi)); +} + +BitRevTrafficPattern::BitRevTrafficPattern(int nodes) + : BitPermutationTrafficPattern(nodes) +{ + +} + +int BitRevTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + int result = 0; + for(int n = _nodes; n > 1; n >>= 1) { + result = (result << 1) | (source % 2); + source >>= 1; + } + return result; +} + +ShuffleTrafficPattern::ShuffleTrafficPattern(int nodes) + : BitPermutationTrafficPattern(nodes) +{ + +} + +int ShuffleTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + int const shifted = source << 1; + return ((shifted & (_nodes - 1)) | bool(shifted & _nodes)); +} + +DigitPermutationTrafficPattern::DigitPermutationTrafficPattern(int nodes, int k, + int n, int xr) + : PermutationTrafficPattern(nodes), _k(k), _n(n), _xr(xr) +{ + +} + +TornadoTrafficPattern::TornadoTrafficPattern(int nodes, int k, int n, int xr) + : DigitPermutationTrafficPattern(nodes, k, n, xr) +{ + +} + +int TornadoTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + + int offset = 1; + int result = 0; + + for(int n = 0; n < _n; ++n) { + result += offset * + (((source / offset) % (_xr * _k) + ((_xr * _k + 1) / 2 - 1)) % (_xr * _k)); + offset *= (_xr * _k); + } + return result; +} + +NeighborTrafficPattern::NeighborTrafficPattern(int nodes, int k, int n, int xr) + : DigitPermutationTrafficPattern(nodes, k, n, xr) +{ + +} + +int NeighborTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + + int offset = 1; + int result = 0; + + for(int n = 0; n < _n; ++n) { + result += offset * + (((source / offset) % (_xr * _k) + 1) % (_xr * _k)); + offset *= (_xr * _k); + } + return result; +} + +RandomPermutationTrafficPattern::RandomPermutationTrafficPattern(int nodes, + int seed) + : TrafficPattern(nodes) +{ + _dest.resize(nodes); + randomize(seed); +} + +void RandomPermutationTrafficPattern::randomize(int seed) +{ + unsigned long prev_seed = RandomIntLong( ); + RandomSeed(seed); + + _dest.assign(_nodes, -1); + + for(int i = 0; i < _nodes; ++i) { + int ind = RandomInt(_nodes - 1 - i); + + int j = 0; + int cnt = 0; + while((cnt < ind) || (_dest[j] != -1)) { + if(_dest[j] == -1) { + ++cnt; + } + ++j; + assert(j < _nodes); + } + + _dest[j] = i; + } + + RandomSeed(prev_seed); +} + +int RandomPermutationTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + assert((_dest[source] >= 0) && (_dest[source] < _nodes)); + return _dest[source]; +} + +RandomTrafficPattern::RandomTrafficPattern(int nodes) + : TrafficPattern(nodes) +{ + +} + +UniformRandomTrafficPattern::UniformRandomTrafficPattern(int nodes) + : RandomTrafficPattern(nodes) +{ + +} + +int UniformRandomTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + return RandomInt(_nodes - 1); +} + +UniformBackgroundTrafficPattern::UniformBackgroundTrafficPattern(int nodes, vector<int> excluded_nodes) + : RandomTrafficPattern(nodes) +{ + for(size_t i = 0; i < excluded_nodes.size(); ++i) { + int const node = excluded_nodes[i]; + assert((node >= 0) && (node < _nodes)); + _excluded.insert(node); + } +} + +int UniformBackgroundTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + + int result; + + do { + result = RandomInt(_nodes - 1); + } while(_excluded.count(result) > 0); + + return result; +} + +DiagonalTrafficPattern::DiagonalTrafficPattern(int nodes) + : RandomTrafficPattern(nodes) +{ + +} + +int DiagonalTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + return ((RandomInt(2) == 0) ? ((source + 1) % _nodes) : source); +} + +AsymmetricTrafficPattern::AsymmetricTrafficPattern(int nodes) + : RandomTrafficPattern(nodes) +{ + +} + +int AsymmetricTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + int const half = _nodes / 2; + return (source % half) + (RandomInt(1) ? half : 0); +} + +Taper64TrafficPattern::Taper64TrafficPattern(int nodes) + : RandomTrafficPattern(nodes) +{ + if(nodes != 64) { + cout << "Error: Tthe Taper64 traffic pattern requires the number of nodes " + << "to be exactly 64." << endl; + exit(-1); + } +} + +int Taper64TrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + if(RandomInt(1)) { + return ((64 + source + 8 * (RandomInt(2) - 1) + (RandomInt(2) - 1)) % 64); + } else { + return RandomInt(_nodes - 1); + } +} + +BadPermDFlyTrafficPattern::BadPermDFlyTrafficPattern(int nodes, int k, int n) + : DigitPermutationTrafficPattern(nodes, k, n, 1) +{ + +} + +int BadPermDFlyTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + + int const grp_size_routers = 2 * _k; + int const grp_size_nodes = grp_size_routers * _k; + + return ((RandomInt(grp_size_nodes - 1) + ((source / grp_size_nodes) + 1) * grp_size_nodes) % _nodes); +} + +BadPermYarcTrafficPattern::BadPermYarcTrafficPattern(int nodes, int k, int n, + int xr) + : DigitPermutationTrafficPattern(nodes, k, n, xr) +{ + +} + +int BadPermYarcTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + int const row = source / (_xr * _k); + return RandomInt((_xr * _k) - 1) * (_xr * _k) + row; +} + +HotSpotTrafficPattern::HotSpotTrafficPattern(int nodes, vector<int> hotspots, + vector<int> rates) + : TrafficPattern(nodes), _hotspots(hotspots), _rates(rates), _max_val(-1) +{ + assert(!_hotspots.empty()); + size_t const size = _hotspots.size(); + _rates.resize(size, _rates.empty() ? 1 : _rates.back()); + for(size_t i = 0; i < size; ++i) { + int const hotspot = _hotspots[i]; + assert((hotspot >= 0) && (hotspot < _nodes)); + int const rate = _rates[i]; + assert(rate >= 0); + _max_val += rate; + } +} + +int HotSpotTrafficPattern::dest(int source) +{ + assert((source >= 0) && (source < _nodes)); + + if(_hotspots.size() == 1) { + return _hotspots[0]; + } + + int pct = RandomInt(_max_val); + + for(size_t i = 0; i < (_hotspots.size() - 1); ++i) { + int const limit = _rates[i]; + if(limit > pct) { + return _hotspots[i]; + } else { + pct -= limit; + } + } + assert(_rates.back() > pct); + return _hotspots.back(); +} diff --git a/src/intersim2/traffic.hpp b/src/intersim2/traffic.hpp new file mode 100644 index 0000000..798b790 --- /dev/null +++ b/src/intersim2/traffic.hpp @@ -0,0 +1,174 @@ +// $Id: traffic.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _TRAFFIC_HPP_ +#define _TRAFFIC_HPP_ + +#include <vector> +#include <set> +#include "config_utils.hpp" + +using namespace std; + +class TrafficPattern { +protected: + int _nodes; + TrafficPattern(int nodes); +public: + virtual ~TrafficPattern() {} + virtual void reset(); + virtual int dest(int source) = 0; + static TrafficPattern * New(string const & pattern, int nodes, + Configuration const * const config = NULL); +}; + +class PermutationTrafficPattern : public TrafficPattern { +protected: + PermutationTrafficPattern(int nodes); +}; + +class BitPermutationTrafficPattern : public PermutationTrafficPattern { +protected: + BitPermutationTrafficPattern(int nodes); +}; + +class BitCompTrafficPattern : public BitPermutationTrafficPattern { +public: + BitCompTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class TransposeTrafficPattern : public BitPermutationTrafficPattern { +protected: + int _shift; +public: + TransposeTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class BitRevTrafficPattern : public BitPermutationTrafficPattern { +public: + BitRevTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class ShuffleTrafficPattern : public BitPermutationTrafficPattern { +public: + ShuffleTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class DigitPermutationTrafficPattern : public PermutationTrafficPattern { +protected: + int _k; + int _n; + int _xr; + DigitPermutationTrafficPattern(int nodes, int k, int n, int xr = 1); +}; + +class TornadoTrafficPattern : public DigitPermutationTrafficPattern { +public: + TornadoTrafficPattern(int nodes, int k, int n, int xr = 1); + virtual int dest(int source); +}; + +class NeighborTrafficPattern : public DigitPermutationTrafficPattern { +public: + NeighborTrafficPattern(int nodes, int k, int n, int xr = 1); + virtual int dest(int source); +}; + +class RandomPermutationTrafficPattern : public TrafficPattern { +private: + vector<int> _dest; + inline void randomize(int seed); +public: + RandomPermutationTrafficPattern(int nodes, int seed); + virtual int dest(int source); +}; + +class RandomTrafficPattern : public TrafficPattern { +protected: + RandomTrafficPattern(int nodes); +}; + +class UniformRandomTrafficPattern : public RandomTrafficPattern { +public: + UniformRandomTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class UniformBackgroundTrafficPattern : public RandomTrafficPattern { +private: + set<int> _excluded; +public: + UniformBackgroundTrafficPattern(int nodes, vector<int> excluded_nodes); + virtual int dest(int source); +}; + +class DiagonalTrafficPattern : public RandomTrafficPattern { +public: + DiagonalTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class AsymmetricTrafficPattern : public RandomTrafficPattern { +public: + AsymmetricTrafficPattern(int nodes); + virtual int dest(int source); +}; + +class Taper64TrafficPattern : public RandomTrafficPattern { +public: + Taper64TrafficPattern(int nodes); + virtual int dest(int source); +}; + +class BadPermDFlyTrafficPattern : public DigitPermutationTrafficPattern { +public: + BadPermDFlyTrafficPattern(int nodes, int k, int n); + virtual int dest(int source); +}; + +class BadPermYarcTrafficPattern : public DigitPermutationTrafficPattern { +public: + BadPermYarcTrafficPattern(int nodes, int k, int n, int xr = 1); + virtual int dest(int source); +}; + +class HotSpotTrafficPattern : public TrafficPattern { +private: + vector<int> _hotspots; + vector<int> _rates; + int _max_val; +public: + HotSpotTrafficPattern(int nodes, vector<int> hotspots, + vector<int> rates = vector<int>()); + virtual int dest(int source); +}; + +#endif diff --git a/src/intersim2/trafficmanager.cpp b/src/intersim2/trafficmanager.cpp new file mode 100644 index 0000000..7b2289c --- /dev/null +++ b/src/intersim2/trafficmanager.cpp @@ -0,0 +1,2287 @@ +// $Id: trafficmanager.cpp 5506 2013-05-07 21:22:23Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#include <sstream> +#include <cmath> +#include <fstream> +#include <limits> +#include <cstdlib> + +#include "booksim.hpp" +#include "booksim_config.hpp" +#include "trafficmanager.hpp" +#include "batchtrafficmanager.hpp" +#include "gputrafficmanager.hpp" +#include "random_utils.hpp" +#include "vc.hpp" +#include "packet_reply_info.hpp" + +TrafficManager * TrafficManager::New(Configuration const & config, + vector<Network *> const & net) +{ + TrafficManager * result = NULL; + string sim_type = config.GetStr("sim_type"); + if((sim_type == "latency") || (sim_type == "throughput")) { + result = new TrafficManager(config, net); + } else if(sim_type == "batch") { + result = new BatchTrafficManager(config, net); + } else if(sim_type == "gpgpusim") { + result = new GPUTrafficManager(config, net); + } + else { + cerr << "Unknown simulation type: " << sim_type << endl; + } + return result; +} + +TrafficManager::TrafficManager( const Configuration &config, const vector<Network *> & net ) +: Module( 0, "traffic_manager" ), _net(net), _empty_network(false), _deadlock_timer(0), _reset_time(0), _drain_time(-1), _cur_id(0), _cur_pid(0), _time(0) +{ + + _nodes = _net[0]->NumNodes( ); + _routers = _net[0]->NumRouters( ); + + _vcs = config.GetInt("num_vcs"); + _subnets = config.GetInt("subnets"); + + _subnet.resize(Flit::NUM_FLIT_TYPES); + _subnet[Flit::READ_REQUEST] = config.GetInt("read_request_subnet"); + _subnet[Flit::READ_REPLY] = config.GetInt("read_reply_subnet"); + _subnet[Flit::WRITE_REQUEST] = config.GetInt("write_request_subnet"); + _subnet[Flit::WRITE_REPLY] = config.GetInt("write_reply_subnet"); + + // ============ Message priorities ============ + + string priority = config.GetStr( "priority" ); + + if ( priority == "class" ) { + _pri_type = class_based; + } else if ( priority == "age" ) { + _pri_type = age_based; + } else if ( priority == "network_age" ) { + _pri_type = network_age_based; + } else if ( priority == "local_age" ) { + _pri_type = local_age_based; + } else if ( priority == "queue_length" ) { + _pri_type = queue_length_based; + } else if ( priority == "hop_count" ) { + _pri_type = hop_count_based; + } else if ( priority == "sequence" ) { + _pri_type = sequence_based; + } else if ( priority == "none" ) { + _pri_type = none; + } else { + Error( "Unkown priority value: " + priority ); + } + + // ============ Routing ============ + + string rf = config.GetStr("routing_function") + "_" + config.GetStr("topology"); + map<string, tRoutingFunction>::const_iterator rf_iter = gRoutingFunctionMap.find(rf); + if(rf_iter == gRoutingFunctionMap.end()) { + Error("Invalid routing function: " + rf); + } + _rf = rf_iter->second; + + _lookahead_routing = !config.GetInt("routing_delay"); + _noq = config.GetInt("noq"); + if(_noq) { + if(!_lookahead_routing) { + Error("NOQ requires lookahead routing to be enabled."); + } + } + + // ============ Traffic ============ + + _classes = config.GetInt("classes"); + + _use_read_write = config.GetIntArray("use_read_write"); + if(_use_read_write.empty()) { + _use_read_write.push_back(config.GetInt("use_read_write")); + } + _use_read_write.resize(_classes, _use_read_write.back()); + + _write_fraction = config.GetFloatArray("write_fraction"); + if(_write_fraction.empty()) { + _write_fraction.push_back(config.GetFloat("write_fraction")); + } + _write_fraction.resize(_classes, _write_fraction.back()); + + _read_request_size = config.GetIntArray("read_request_size"); + if(_read_request_size.empty()) { + _read_request_size.push_back(config.GetInt("read_request_size")); + } + _read_request_size.resize(_classes, _read_request_size.back()); + + _read_reply_size = config.GetIntArray("read_reply_size"); + if(_read_reply_size.empty()) { + _read_reply_size.push_back(config.GetInt("read_reply_size")); + } + _read_reply_size.resize(_classes, _read_reply_size.back()); + + _write_request_size = config.GetIntArray("write_request_size"); + if(_write_request_size.empty()) { + _write_request_size.push_back(config.GetInt("write_request_size")); + } + _write_request_size.resize(_classes, _write_request_size.back()); + + _write_reply_size = config.GetIntArray("write_reply_size"); + if(_write_reply_size.empty()) { + _write_reply_size.push_back(config.GetInt("write_reply_size")); + } + _write_reply_size.resize(_classes, _write_reply_size.back()); + + string packet_size_str = config.GetStr("packet_size"); + if(packet_size_str.empty()) { + _packet_size.push_back(vector<int>(1, config.GetInt("packet_size"))); + } else { + vector<string> packet_size_strings = tokenize_str(packet_size_str); + for(size_t i = 0; i < packet_size_strings.size(); ++i) { + _packet_size.push_back(tokenize_int(packet_size_strings[i])); + } + } + _packet_size.resize(_classes, _packet_size.back()); + + string packet_size_rate_str = config.GetStr("packet_size_rate"); + if(packet_size_rate_str.empty()) { + int rate = config.GetInt("packet_size_rate"); + assert(rate >= 0); + for(int c = 0; c < _classes; ++c) { + int size = _packet_size[c].size(); + _packet_size_rate.push_back(vector<int>(size, rate)); + _packet_size_max_val.push_back(size * rate - 1); + } + } else { + vector<string> packet_size_rate_strings = tokenize_str(packet_size_rate_str); + packet_size_rate_strings.resize(_classes, packet_size_rate_strings.back()); + for(int c = 0; c < _classes; ++c) { + vector<int> rates = tokenize_int(packet_size_rate_strings[c]); + rates.resize(_packet_size[c].size(), rates.back()); + _packet_size_rate.push_back(rates); + int size = rates.size(); + int max_val = -1; + for(int i = 0; i < size; ++i) { + int rate = rates[i]; + assert(rate >= 0); + max_val += rate; + } + _packet_size_max_val.push_back(max_val); + } + } + + for(int c = 0; c < _classes; ++c) { + if(_use_read_write[c]) { + _packet_size[c] = + vector<int>(1, (_read_request_size[c] + _read_reply_size[c] + + _write_request_size[c] + _write_reply_size[c]) / 2); + _packet_size_rate[c] = vector<int>(1, 1); + _packet_size_max_val[c] = 0; + } + } + + _load = config.GetFloatArray("injection_rate"); + if(_load.empty()) { + _load.push_back(config.GetFloat("injection_rate")); + } + _load.resize(_classes, _load.back()); + + if(config.GetInt("injection_rate_uses_flits")) { + for(int c = 0; c < _classes; ++c) + _load[c] /= _GetAveragePacketSize(c); + } + + _traffic = config.GetStrArray("traffic"); + _traffic.resize(_classes, _traffic.back()); + + _traffic_pattern.resize(_classes); + + _class_priority = config.GetIntArray("class_priority"); + if(_class_priority.empty()) { + _class_priority.push_back(config.GetInt("class_priority")); + } + _class_priority.resize(_classes, _class_priority.back()); + + vector<string> injection_process = config.GetStrArray("injection_process"); + injection_process.resize(_classes, injection_process.back()); + + _injection_process.resize(_classes); + + for(int c = 0; c < _classes; ++c) { + _traffic_pattern[c] = TrafficPattern::New(_traffic[c], _nodes, &config); + _injection_process[c] = InjectionProcess::New(injection_process[c], _nodes, _load[c], &config); + } + + // ============ Injection VC states ============ + + _buf_states.resize(_nodes); + _last_vc.resize(_nodes); + _last_class.resize(_nodes); + + for ( int source = 0; source < _nodes; ++source ) { + _buf_states[source].resize(_subnets); + _last_class[source].resize(_subnets, 0); + _last_vc[source].resize(_subnets); + for ( int subnet = 0; subnet < _subnets; ++subnet ) { + ostringstream tmp_name; + tmp_name << "terminal_buf_state_" << source << "_" << subnet; + BufferState * bs = new BufferState( config, this, tmp_name.str( ) ); + int vc_alloc_delay = config.GetInt("vc_alloc_delay"); + int sw_alloc_delay = config.GetInt("sw_alloc_delay"); + int router_latency = config.GetInt("routing_delay") + (config.GetInt("speculative") ? max(vc_alloc_delay, sw_alloc_delay) : (vc_alloc_delay + sw_alloc_delay)); + int min_latency = 1 + _net[subnet]->GetInject(source)->GetLatency() + router_latency + _net[subnet]->GetInjectCred(source)->GetLatency(); + bs->SetMinLatency(min_latency); + _buf_states[source][subnet] = bs; + _last_vc[source][subnet].resize(_classes, -1); + } + } + +#ifdef TRACK_FLOWS + _outstanding_credits.resize(_classes); + for(int c = 0; c < _classes; ++c) { + _outstanding_credits[c].resize(_subnets, vector<int>(_nodes, 0)); + } + _outstanding_classes.resize(_nodes); + for(int n = 0; n < _nodes; ++n) { + _outstanding_classes[n].resize(_subnets, vector<queue<int> >(_vcs)); + } +#endif + + // ============ Injection queues ============ + + _qtime.resize(_nodes); + _qdrained.resize(_nodes); + _partial_packets.resize(_nodes); + + for ( int s = 0; s < _nodes; ++s ) { + _qtime[s].resize(_classes); + _qdrained[s].resize(_classes); + _partial_packets[s].resize(_classes); + } + + _total_in_flight_flits.resize(_classes); + _measured_in_flight_flits.resize(_classes); + _retired_packets.resize(_classes); + + _packet_seq_no.resize(_nodes); + _repliesPending.resize(_nodes); + _requestsOutstanding.resize(_nodes); + + _hold_switch_for_packet = config.GetInt("hold_switch_for_packet"); + + // ============ Simulation parameters ============ + + _total_sims = config.GetInt( "sim_count" ); + + _router.resize(_subnets); + for (int i=0; i < _subnets; ++i) { + _router[i] = _net[i]->GetRouters(); + } + + //seed the network + RandomSeed(config.GetInt("seed")); + + _measure_latency = (config.GetStr("sim_type") == "latency"); + + _sample_period = config.GetInt( "sample_period" ); + _max_samples = config.GetInt( "max_samples" ); + _warmup_periods = config.GetInt( "warmup_periods" ); + + _measure_stats = config.GetIntArray( "measure_stats" ); + if(_measure_stats.empty()) { + _measure_stats.push_back(config.GetInt("measure_stats")); + } + _measure_stats.resize(_classes, _measure_stats.back()); + _pair_stats = (config.GetInt("pair_stats")==1); + + _latency_thres = config.GetFloatArray( "latency_thres" ); + if(_latency_thres.empty()) { + _latency_thres.push_back(config.GetFloat("latency_thres")); + } + _latency_thres.resize(_classes, _latency_thres.back()); + + _warmup_threshold = config.GetFloatArray( "warmup_thres" ); + if(_warmup_threshold.empty()) { + _warmup_threshold.push_back(config.GetFloat("warmup_thres")); + } + _warmup_threshold.resize(_classes, _warmup_threshold.back()); + + _acc_warmup_threshold = config.GetFloatArray( "acc_warmup_thres" ); + if(_acc_warmup_threshold.empty()) { + _acc_warmup_threshold.push_back(config.GetFloat("acc_warmup_thres")); + } + _acc_warmup_threshold.resize(_classes, _acc_warmup_threshold.back()); + + _stopping_threshold = config.GetFloatArray( "stopping_thres" ); + if(_stopping_threshold.empty()) { + _stopping_threshold.push_back(config.GetFloat("stopping_thres")); + } + _stopping_threshold.resize(_classes, _stopping_threshold.back()); + + _acc_stopping_threshold = config.GetFloatArray( "acc_stopping_thres" ); + if(_acc_stopping_threshold.empty()) { + _acc_stopping_threshold.push_back(config.GetFloat("acc_stopping_thres")); + } + _acc_stopping_threshold.resize(_classes, _acc_stopping_threshold.back()); + + _include_queuing = config.GetInt( "include_queuing" ); + + _print_csv_results = config.GetInt( "print_csv_results" ); + _deadlock_warn_timeout = config.GetInt( "deadlock_warn_timeout" ); + + string watch_file = config.GetStr( "watch_file" ); + if((watch_file != "") && (watch_file != "-")) { + _LoadWatchList(watch_file); + } + + vector<int> watch_flits = config.GetIntArray("watch_flits"); + for(size_t i = 0; i < watch_flits.size(); ++i) { + _flits_to_watch.insert(watch_flits[i]); + } + + vector<int> watch_packets = config.GetIntArray("watch_packets"); + for(size_t i = 0; i < watch_packets.size(); ++i) { + _packets_to_watch.insert(watch_packets[i]); + } + + string stats_out_file = config.GetStr( "stats_out" ); + if(stats_out_file == "") { + _stats_out = NULL; + } else if(stats_out_file == "-") { + _stats_out = &cout; + } else { + _stats_out = new ofstream(stats_out_file.c_str()); + config.WriteMatlabFile(_stats_out); + } + +#ifdef TRACK_FLOWS + _injected_flits.resize(_classes, vector<int>(_nodes, 0)); + _ejected_flits.resize(_classes, vector<int>(_nodes, 0)); + string injected_flits_out_file = config.GetStr( "injected_flits_out" ); + if(injected_flits_out_file == "") { + _injected_flits_out = NULL; + } else { + _injected_flits_out = new ofstream(injected_flits_out_file.c_str()); + } + string received_flits_out_file = config.GetStr( "received_flits_out" ); + if(received_flits_out_file == "") { + _received_flits_out = NULL; + } else { + _received_flits_out = new ofstream(received_flits_out_file.c_str()); + } + string stored_flits_out_file = config.GetStr( "stored_flits_out" ); + if(stored_flits_out_file == "") { + _stored_flits_out = NULL; + } else { + _stored_flits_out = new ofstream(stored_flits_out_file.c_str()); + } + string sent_flits_out_file = config.GetStr( "sent_flits_out" ); + if(sent_flits_out_file == "") { + _sent_flits_out = NULL; + } else { + _sent_flits_out = new ofstream(sent_flits_out_file.c_str()); + } + string outstanding_credits_out_file = config.GetStr( "outstanding_credits_out" ); + if(outstanding_credits_out_file == "") { + _outstanding_credits_out = NULL; + } else { + _outstanding_credits_out = new ofstream(outstanding_credits_out_file.c_str()); + } + string ejected_flits_out_file = config.GetStr( "ejected_flits_out" ); + if(ejected_flits_out_file == "") { + _ejected_flits_out = NULL; + } else { + _ejected_flits_out = new ofstream(ejected_flits_out_file.c_str()); + } + string active_packets_out_file = config.GetStr( "active_packets_out" ); + if(active_packets_out_file == "") { + _active_packets_out = NULL; + } else { + _active_packets_out = new ofstream(active_packets_out_file.c_str()); + } +#endif + +#ifdef TRACK_CREDITS + string used_credits_out_file = config.GetStr( "used_credits_out" ); + if(used_credits_out_file == "") { + _used_credits_out = NULL; + } else { + _used_credits_out = new ofstream(used_credits_out_file.c_str()); + } + string free_credits_out_file = config.GetStr( "free_credits_out" ); + if(free_credits_out_file == "") { + _free_credits_out = NULL; + } else { + _free_credits_out = new ofstream(free_credits_out_file.c_str()); + } + string max_credits_out_file = config.GetStr( "max_credits_out" ); + if(max_credits_out_file == "") { + _max_credits_out = NULL; + } else { + _max_credits_out = new ofstream(max_credits_out_file.c_str()); + } +#endif + + // ============ Statistics ============ + + _plat_stats.resize(_classes); + _overall_min_plat.resize(_classes, 0.0); + _overall_avg_plat.resize(_classes, 0.0); + _overall_max_plat.resize(_classes, 0.0); + + _nlat_stats.resize(_classes); + _overall_min_nlat.resize(_classes, 0.0); + _overall_avg_nlat.resize(_classes, 0.0); + _overall_max_nlat.resize(_classes, 0.0); + + _flat_stats.resize(_classes); + _overall_min_flat.resize(_classes, 0.0); + _overall_avg_flat.resize(_classes, 0.0); + _overall_max_flat.resize(_classes, 0.0); + + _frag_stats.resize(_classes); + _overall_min_frag.resize(_classes, 0.0); + _overall_avg_frag.resize(_classes, 0.0); + _overall_max_frag.resize(_classes, 0.0); + + if(_pair_stats){ + _pair_plat.resize(_classes); + _pair_nlat.resize(_classes); + _pair_flat.resize(_classes); + } + + _hop_stats.resize(_classes); + _overall_hop_stats.resize(_classes, 0.0); + + _sent_packets.resize(_classes); + _overall_min_sent_packets.resize(_classes, 0.0); + _overall_avg_sent_packets.resize(_classes, 0.0); + _overall_max_sent_packets.resize(_classes, 0.0); + _accepted_packets.resize(_classes); + _overall_min_accepted_packets.resize(_classes, 0.0); + _overall_avg_accepted_packets.resize(_classes, 0.0); + _overall_max_accepted_packets.resize(_classes, 0.0); + + _sent_flits.resize(_classes); + _overall_min_sent.resize(_classes, 0.0); + _overall_avg_sent.resize(_classes, 0.0); + _overall_max_sent.resize(_classes, 0.0); + _accepted_flits.resize(_classes); + _overall_min_accepted.resize(_classes, 0.0); + _overall_avg_accepted.resize(_classes, 0.0); + _overall_max_accepted.resize(_classes, 0.0); + +#ifdef TRACK_STALLS + _buffer_busy_stalls.resize(_classes); + _buffer_conflict_stalls.resize(_classes); + _buffer_full_stalls.resize(_classes); + _buffer_reserved_stalls.resize(_classes); + _crossbar_conflict_stalls.resize(_classes); + _overall_buffer_busy_stalls.resize(_classes, 0); + _overall_buffer_conflict_stalls.resize(_classes, 0); + _overall_buffer_full_stalls.resize(_classes, 0); + _overall_buffer_reserved_stalls.resize(_classes, 0); + _overall_crossbar_conflict_stalls.resize(_classes, 0); +#endif + + for ( int c = 0; c < _classes; ++c ) { + ostringstream tmp_name; + + tmp_name << "plat_stat_" << c; + _plat_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 ); + _stats[tmp_name.str()] = _plat_stats[c]; + tmp_name.str(""); + + tmp_name << "nlat_stat_" << c; + _nlat_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 ); + _stats[tmp_name.str()] = _nlat_stats[c]; + tmp_name.str(""); + + tmp_name << "flat_stat_" << c; + _flat_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 1000 ); + _stats[tmp_name.str()] = _flat_stats[c]; + tmp_name.str(""); + + tmp_name << "frag_stat_" << c; + _frag_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 100 ); + _stats[tmp_name.str()] = _frag_stats[c]; + tmp_name.str(""); + + tmp_name << "hop_stat_" << c; + _hop_stats[c] = new Stats( this, tmp_name.str( ), 1.0, 20 ); + _stats[tmp_name.str()] = _hop_stats[c]; + tmp_name.str(""); + + if(_pair_stats){ + _pair_plat[c].resize(_nodes*_nodes); + _pair_nlat[c].resize(_nodes*_nodes); + _pair_flat[c].resize(_nodes*_nodes); + } + + _sent_packets[c].resize(_nodes, 0); + _accepted_packets[c].resize(_nodes, 0); + _sent_flits[c].resize(_nodes, 0); + _accepted_flits[c].resize(_nodes, 0); + +#ifdef TRACK_STALLS + _buffer_busy_stalls[c].resize(_subnets*_routers, 0); + _buffer_conflict_stalls[c].resize(_subnets*_routers, 0); + _buffer_full_stalls[c].resize(_subnets*_routers, 0); + _buffer_reserved_stalls[c].resize(_subnets*_routers, 0); + _crossbar_conflict_stalls[c].resize(_subnets*_routers, 0); +#endif + if(_pair_stats){ + for ( int i = 0; i < _nodes; ++i ) { + for ( int j = 0; j < _nodes; ++j ) { + tmp_name << "pair_plat_stat_" << c << "_" << i << "_" << j; + _pair_plat[c][i*_nodes+j] = new Stats( this, tmp_name.str( ), 1.0, 250 ); + _stats[tmp_name.str()] = _pair_plat[c][i*_nodes+j]; + tmp_name.str(""); + + tmp_name << "pair_nlat_stat_" << c << "_" << i << "_" << j; + _pair_nlat[c][i*_nodes+j] = new Stats( this, tmp_name.str( ), 1.0, 250 ); + _stats[tmp_name.str()] = _pair_nlat[c][i*_nodes+j]; + tmp_name.str(""); + + tmp_name << "pair_flat_stat_" << c << "_" << i << "_" << j; + _pair_flat[c][i*_nodes+j] = new Stats( this, tmp_name.str( ), 1.0, 250 ); + _stats[tmp_name.str()] = _pair_flat[c][i*_nodes+j]; + tmp_name.str(""); + } + } + } + } + + _slowest_flit.resize(_classes, -1); + _slowest_packet.resize(_classes, -1); + + + +} + +TrafficManager::~TrafficManager( ) +{ + + for ( int source = 0; source < _nodes; ++source ) { + for ( int subnet = 0; subnet < _subnets; ++subnet ) { + delete _buf_states[source][subnet]; + } + } + + for ( int c = 0; c < _classes; ++c ) { + delete _plat_stats[c]; + delete _nlat_stats[c]; + delete _flat_stats[c]; + delete _frag_stats[c]; + delete _hop_stats[c]; + + delete _traffic_pattern[c]; + delete _injection_process[c]; + if(_pair_stats){ + for ( int i = 0; i < _nodes; ++i ) { + for ( int j = 0; j < _nodes; ++j ) { + delete _pair_plat[c][i*_nodes+j]; + delete _pair_nlat[c][i*_nodes+j]; + delete _pair_flat[c][i*_nodes+j]; + } + } + } + } + + if(gWatchOut && (gWatchOut != &cout)) delete gWatchOut; + if(_stats_out && (_stats_out != &cout)) delete _stats_out; + +#ifdef TRACK_FLOWS + if(_injected_flits_out) delete _injected_flits_out; + if(_received_flits_out) delete _received_flits_out; + if(_stored_flits_out) delete _stored_flits_out; + if(_sent_flits_out) delete _sent_flits_out; + if(_outstanding_credits_out) delete _outstanding_credits_out; + if(_ejected_flits_out) delete _ejected_flits_out; + if(_active_packets_out) delete _active_packets_out; +#endif + +#ifdef TRACK_CREDITS + if(_used_credits_out) delete _used_credits_out; + if(_free_credits_out) delete _free_credits_out; + if(_max_credits_out) delete _max_credits_out; +#endif + + PacketReplyInfo::FreeAll(); + Flit::FreeAll(); + Credit::FreeAll(); +} + + +void TrafficManager::_RetireFlit( Flit *f, int dest ) +{ + _deadlock_timer = 0; + + assert(_total_in_flight_flits[f->cl].count(f->id) > 0); + _total_in_flight_flits[f->cl].erase(f->id); + + if(f->record) { + assert(_measured_in_flight_flits[f->cl].count(f->id) > 0); + _measured_in_flight_flits[f->cl].erase(f->id); + } + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << dest << " | " + << "Retiring flit " << f->id + << " (packet " << f->pid + << ", src = " << f->src + << ", dest = " << f->dest + << ", hops = " << f->hops + << ", flat = " << f->atime - f->itime + << ")." << endl; + } + + if ( f->head && ( f->dest != dest ) ) { + ostringstream err; + err << "Flit " << f->id << " arrived at incorrect output " << dest; + Error( err.str( ) ); + } + + if((_slowest_flit[f->cl] < 0) || + (_flat_stats[f->cl]->Max() < (f->atime - f->itime))) + _slowest_flit[f->cl] = f->id; + _flat_stats[f->cl]->AddSample( f->atime - f->itime); + if(_pair_stats){ + _pair_flat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - f->itime ); + } + + if ( f->tail ) { + Flit * head; + if(f->head) { + head = f; + } else { + map<int, Flit *>::iterator iter = _retired_packets[f->cl].find(f->pid); + assert(iter != _retired_packets[f->cl].end()); + head = iter->second; + _retired_packets[f->cl].erase(iter); + assert(head->head); + assert(f->pid == head->pid); + } + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << dest << " | " + << "Retiring packet " << f->pid + << " (plat = " << f->atime - head->ctime + << ", nlat = " << f->atime - head->itime + << ", frag = " << (f->atime - head->atime) - (f->id - head->id) // NB: In the spirit of solving problems using ugly hacks, we compute the packet length by taking advantage of the fact that the IDs of flits within a packet are contiguous. + << ", src = " << head->src + << ", dest = " << head->dest + << ")." << endl; + } + + //code the source of request, look carefully, its tricky ;) + if (f->type == Flit::READ_REQUEST || f->type == Flit::WRITE_REQUEST) { + PacketReplyInfo* rinfo = PacketReplyInfo::New(); + rinfo->source = f->src; + rinfo->time = f->atime; + rinfo->record = f->record; + rinfo->type = f->type; + _repliesPending[dest].push_back(rinfo); + } else { + if(f->type == Flit::READ_REPLY || f->type == Flit::WRITE_REPLY ){ + _requestsOutstanding[dest]--; + } else if(f->type == Flit::ANY_TYPE) { + _requestsOutstanding[f->src]--; + } + + } + + // Only record statistics once per packet (at tail) + // and based on the simulation state + if ( ( _sim_state == warming_up ) || f->record ) { + + _hop_stats[f->cl]->AddSample( f->hops ); + + if((_slowest_packet[f->cl] < 0) || + (_plat_stats[f->cl]->Max() < (f->atime - head->itime))) + _slowest_packet[f->cl] = f->pid; + _plat_stats[f->cl]->AddSample( f->atime - head->ctime); + _nlat_stats[f->cl]->AddSample( f->atime - head->itime); + _frag_stats[f->cl]->AddSample( (f->atime - head->atime) - (f->id - head->id) ); + + if(_pair_stats){ + _pair_plat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->ctime ); + _pair_nlat[f->cl][f->src*_nodes+dest]->AddSample( f->atime - head->itime ); + } + } + + if(f != head) { + head->Free(); + } + + } + + if(f->head && !f->tail) { + _retired_packets[f->cl].insert(make_pair(f->pid, f)); + } else { + f->Free(); + } +} + +int TrafficManager::_IssuePacket( int source, int cl ) +{ + int result = 0; + if(_use_read_write[cl]){ //use read and write + //check queue for waiting replies. + //check to make sure it is on time yet + if (!_repliesPending[source].empty()) { + if(_repliesPending[source].front()->time <= _time) { + result = -1; + } + } else { + + //produce a packet + if(_injection_process[cl]->test(source)) { + + //coin toss to determine request type. + result = (RandomFloat() < _write_fraction[cl]) ? 2 : 1; + + _requestsOutstanding[source]++; + } + } + } else { //normal mode + result = _injection_process[cl]->test(source) ? 1 : 0; + _requestsOutstanding[source]++; + } + if(result != 0) { + _packet_seq_no[source]++; + } + return result; +} + +void TrafficManager::_GeneratePacket( int source, int stype, + int cl, int time ) +{ + assert(stype!=0); + + Flit::FlitType packet_type = Flit::ANY_TYPE; + int size = _GetNextPacketSize(cl); //input size + int pid = _cur_pid++; + assert(_cur_pid); + int packet_destination = _traffic_pattern[cl]->dest(source); + bool record = false; + bool watch = gWatchOut && (_packets_to_watch.count(pid) > 0); + if(_use_read_write[cl]){ + if(stype > 0) { + if (stype == 1) { + packet_type = Flit::READ_REQUEST; + size = _read_request_size[cl]; + } else if (stype == 2) { + packet_type = Flit::WRITE_REQUEST; + size = _write_request_size[cl]; + } else { + ostringstream err; + err << "Invalid packet type: " << packet_type; + Error( err.str( ) ); + } + } else { + PacketReplyInfo* rinfo = _repliesPending[source].front(); + if (rinfo->type == Flit::READ_REQUEST) {//read reply + size = _read_reply_size[cl]; + packet_type = Flit::READ_REPLY; + } else if(rinfo->type == Flit::WRITE_REQUEST) { //write reply + size = _write_reply_size[cl]; + packet_type = Flit::WRITE_REPLY; + } else { + ostringstream err; + err << "Invalid packet type: " << rinfo->type; + Error( err.str( ) ); + } + packet_destination = rinfo->source; + time = rinfo->time; + record = rinfo->record; + _repliesPending[source].pop_front(); + rinfo->Free(); + } + } + + if ((packet_destination <0) || (packet_destination >= _nodes)) { + ostringstream err; + err << "Incorrect packet destination " << packet_destination + << " for stype " << packet_type; + Error( err.str( ) ); + } + + if ( ( _sim_state == running ) || + ( ( _sim_state == draining ) && ( time < _drain_time ) ) ) { + record = _measure_stats[cl]; + } + + int subnetwork = ((packet_type == Flit::ANY_TYPE) ? + RandomInt(_subnets-1) : + _subnet[packet_type]); + + if ( watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << source << " | " + << "Enqueuing packet " << pid + << " at time " << time + << "." << endl; + } + + for ( int i = 0; i < size; ++i ) { + Flit * f = Flit::New(); + f->id = _cur_id++; + assert(_cur_id); + f->pid = pid; + f->watch = watch | (gWatchOut && (_flits_to_watch.count(f->id) > 0)); + f->subnetwork = subnetwork; + f->src = source; + f->ctime = time; + f->record = record; + f->cl = cl; + + _total_in_flight_flits[f->cl].insert(make_pair(f->id, f)); + if(record) { + _measured_in_flight_flits[f->cl].insert(make_pair(f->id, f)); + } + + if(gTrace){ + cout<<"New Flit "<<f->src<<endl; + } + f->type = packet_type; + + if ( i == 0 ) { // Head flit + f->head = true; + //packets are only generated to nodes smaller or equal to limit + f->dest = packet_destination; + } else { + f->head = false; + f->dest = -1; + } + switch( _pri_type ) { + case class_based: + f->pri = _class_priority[cl]; + assert(f->pri >= 0); + break; + case age_based: + f->pri = numeric_limits<int>::max() - time; + assert(f->pri >= 0); + break; + case sequence_based: + f->pri = numeric_limits<int>::max() - _packet_seq_no[source]; + assert(f->pri >= 0); + break; + default: + f->pri = 0; + } + if ( i == ( size - 1 ) ) { // Tail flit + f->tail = true; + } else { + f->tail = false; + } + + f->vc = -1; + + if ( f->watch ) { + *gWatchOut << GetSimTime() << " | " + << "node" << source << " | " + << "Enqueuing flit " << f->id + << " (packet " << f->pid + << ") at time " << time + << "." << endl; + } + + _partial_packets[source][cl].push_back( f ); + } +} + +void TrafficManager::_Inject(){ + + for ( int input = 0; input < _nodes; ++input ) { + for ( int c = 0; c < _classes; ++c ) { + // Potentially generate packets for any (input,class) + // that is currently empty + if ( _partial_packets[input][c].empty() ) { + bool generated = false; + while( !generated && ( _qtime[input][c] <= _time ) ) { + int stype = _IssuePacket( input, c ); + + if ( stype != 0 ) { //generate a packet + _GeneratePacket( input, stype, c, + _include_queuing==1 ? + _qtime[input][c] : _time ); + generated = true; + } + // only advance time if this is not a reply packet + if(!_use_read_write[c] || (stype >= 0)){ + ++_qtime[input][c]; + } + } + + if ( ( _sim_state == draining ) && + ( _qtime[input][c] > _drain_time ) ) { + _qdrained[input][c] = true; + } + } + } + } +} + +void TrafficManager::_Step( ) +{ + bool flits_in_flight = false; + for(int c = 0; c < _classes; ++c) { + flits_in_flight |= !_total_in_flight_flits[c].empty(); + } + if(flits_in_flight && (_deadlock_timer++ >= _deadlock_warn_timeout)){ + _deadlock_timer = 0; + cout << "WARNING: Possible network deadlock.\n"; + } + + vector<map<int, Flit *> > flits(_subnets); + + for ( int subnet = 0; subnet < _subnets; ++subnet ) { + for ( int n = 0; n < _nodes; ++n ) { + Flit * const f = _net[subnet]->ReadFlit( n ); + if ( f ) { + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Ejecting flit " << f->id + << " (packet " << f->pid << ")" + << " from VC " << f->vc + << "." << endl; + } + flits[subnet].insert(make_pair(n, f)); + if((_sim_state == warming_up) || (_sim_state == running)) { + ++_accepted_flits[f->cl][n]; + if(f->tail) { + ++_accepted_packets[f->cl][n]; + } + } + } + + Credit * const c = _net[subnet]->ReadCredit( n ); + if ( c ) { +#ifdef TRACK_FLOWS + for(set<int>::const_iterator iter = c->vc.begin(); iter != c->vc.end(); ++iter) { + int const vc = *iter; + assert(!_outstanding_classes[n][subnet][vc].empty()); + int cl = _outstanding_classes[n][subnet][vc].front(); + _outstanding_classes[n][subnet][vc].pop(); + assert(_outstanding_credits[cl][subnet][n] > 0); + --_outstanding_credits[cl][subnet][n]; + } +#endif + _buf_states[n][subnet]->ProcessCredit(c); + c->Free(); + } + } + _net[subnet]->ReadInputs( ); + } + + if ( !_empty_network ) { + _Inject(); + } + + for(int subnet = 0; subnet < _subnets; ++subnet) { + + for(int n = 0; n < _nodes; ++n) { + + Flit * f = NULL; + + BufferState * const dest_buf = _buf_states[n][subnet]; + + int const last_class = _last_class[n][subnet]; + + int class_limit = _classes; + + if(_hold_switch_for_packet) { + list<Flit *> const & pp = _partial_packets[n][last_class]; + if(!pp.empty() && !pp.front()->head && + !dest_buf->IsFullFor(pp.front()->vc)) { + f = pp.front(); + assert(f->vc == _last_vc[n][subnet][last_class]); + + // if we're holding the connection, we don't need to check that class + // again in the for loop + --class_limit; + } + } + + for(int i = 1; i <= class_limit; ++i) { + + int const c = (last_class + i) % _classes; + + list<Flit *> const & pp = _partial_packets[n][c]; + + if(pp.empty()) { + continue; + } + + Flit * const cf = pp.front(); + assert(cf); + assert(cf->cl == c); + + if(cf->subnetwork != subnet) { + continue; + } + + if(f && (f->pri >= cf->pri)) { + continue; + } + + if(cf->head && cf->vc == -1) { // Find first available VC + + OutputSet route_set; + _rf(NULL, cf, -1, &route_set, true); + set<OutputSet::sSetElement> const & os = route_set.GetSet(); + assert(os.size() == 1); + OutputSet::sSetElement const & se = *os.begin(); + assert(se.output_port == -1); + int vc_start = se.vc_start; + int vc_end = se.vc_end; + int vc_count = vc_end - vc_start + 1; + if(_noq) { + assert(_lookahead_routing); + const FlitChannel * inject = _net[subnet]->GetInject(n); + const Router * router = inject->GetSink(); + assert(router); + int in_channel = inject->GetSinkPort(); + + // NOTE: Because the lookahead is not for injection, but for the + // first hop, we have to temporarily set cf's VC to be non-negative + // in order to avoid seting of an assertion in the routing function. + cf->vc = vc_start; + _rf(router, cf, in_channel, &cf->la_route_set, false); + cf->vc = -1; + + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Generating lookahead routing info for flit " << cf->id + << " (NOQ)." << endl; + } + set<OutputSet::sSetElement> const sl = cf->la_route_set.GetSet(); + assert(sl.size() == 1); + int next_output = sl.begin()->output_port; + vc_count /= router->NumOutputs(); + vc_start += next_output * vc_count; + vc_end = vc_start + vc_count - 1; + assert(vc_start >= se.vc_start && vc_start <= se.vc_end); + assert(vc_end >= se.vc_start && vc_end <= se.vc_end); + assert(vc_start <= vc_end); + } + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Finding output VC for flit " << cf->id + << ":" << endl; + } + for(int i = 1; i <= vc_count; ++i) { + int const lvc = _last_vc[n][subnet][c]; + int const vc = + (lvc < vc_start || lvc > vc_end) ? + vc_start : + (vc_start + (lvc - vc_start + i) % vc_count); + assert((vc >= vc_start) && (vc <= vc_end)); + if(!dest_buf->IsAvailableFor(vc)) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Output VC " << vc << " is busy." << endl; + } + } else { + if(dest_buf->IsFullFor(vc)) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Output VC " << vc << " is full." << endl; + } + } else { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << " Selected output VC " << vc << "." << endl; + } + cf->vc = vc; + break; + } + } + } + } + + if(cf->vc == -1) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "No output VC found for flit " << cf->id + << "." << endl; + } + } else { + if(dest_buf->IsFullFor(cf->vc)) { + if(cf->watch) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Selected output VC " << cf->vc + << " is full for flit " << cf->id + << "." << endl; + } + } else { + f = cf; + } + } + } + + if(f) { + + assert(f->subnetwork == subnet); + + int const c = f->cl; + + if(f->head) { + + if (_lookahead_routing) { + if(!_noq) { + const FlitChannel * inject = _net[subnet]->GetInject(n); + const Router * router = inject->GetSink(); + assert(router); + int in_channel = inject->GetSinkPort(); + _rf(router, f, in_channel, &f->la_route_set, false); + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Generating lookahead routing info for flit " << f->id + << "." << endl; + } + } else if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Already generated lookahead routing info for flit " << f->id + << " (NOQ)." << endl; + } + } else { + f->la_route_set.Clear(); + } + + dest_buf->TakeBuffer(f->vc); + _last_vc[n][subnet][c] = f->vc; + } + + _last_class[n][subnet] = c; + + _partial_packets[n][c].pop_front(); + +#ifdef TRACK_FLOWS + ++_outstanding_credits[c][subnet][n]; + _outstanding_classes[n][subnet][f->vc].push(c); +#endif + + dest_buf->SendingFlit(f); + + if(_pri_type == network_age_based) { + f->pri = numeric_limits<int>::max() - _time; + assert(f->pri >= 0); + } + + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Injecting flit " << f->id + << " into subnet " << subnet + << " at time " << _time + << " with priority " << f->pri + << "." << endl; + } + f->itime = _time; + + // Pass VC "back" + if(!_partial_packets[n][c].empty() && !f->tail) { + Flit * const nf = _partial_packets[n][c].front(); + nf->vc = f->vc; + } + + if((_sim_state == warming_up) || (_sim_state == running)) { + ++_sent_flits[c][n]; + if(f->head) { + ++_sent_packets[c][n]; + } + } + +#ifdef TRACK_FLOWS + ++_injected_flits[c][n]; +#endif + + _net[subnet]->WriteFlit(f, n); + + } + } + } + + for(int subnet = 0; subnet < _subnets; ++subnet) { + for(int n = 0; n < _nodes; ++n) { + map<int, Flit *>::const_iterator iter = flits[subnet].find(n); + if(iter != flits[subnet].end()) { + Flit * const f = iter->second; + + f->atime = _time; + if(f->watch) { + *gWatchOut << GetSimTime() << " | " + << "node" << n << " | " + << "Injecting credit for VC " << f->vc + << " into subnet " << subnet + << "." << endl; + } + Credit * const c = Credit::New(); + c->vc.insert(f->vc); + _net[subnet]->WriteCredit(c, n); + +#ifdef TRACK_FLOWS + ++_ejected_flits[f->cl][n]; +#endif + + _RetireFlit(f, n); + } + } + flits[subnet].clear(); + _net[subnet]->Evaluate( ); + _net[subnet]->WriteOutputs( ); + } + + ++_time; + assert(_time); + if(gTrace){ + cout<<"TIME "<<_time<<endl; + } + +} + +bool TrafficManager::_PacketsOutstanding( ) const +{ + for ( int c = 0; c < _classes; ++c ) { + if ( _measure_stats[c] ) { + if ( _measured_in_flight_flits[c].empty() ) { + + for ( int s = 0; s < _nodes; ++s ) { + if ( !_qdrained[s][c] ) { +#ifdef DEBUG_DRAIN + cout << "waiting on queue " << s << " class " << c; + cout << ", time = " << _time << " qtime = " << _qtime[s][c] << endl; +#endif + return true; + } + } + } else { +#ifdef DEBUG_DRAIN + cout << "in flight = " << _measured_in_flight_flits[c].size() << endl; +#endif + return true; + } + } + } + return false; +} + +void TrafficManager::_ClearStats( ) +{ + _slowest_flit.assign(_classes, -1); + _slowest_packet.assign(_classes, -1); + + for ( int c = 0; c < _classes; ++c ) { + + _plat_stats[c]->Clear( ); + _nlat_stats[c]->Clear( ); + _flat_stats[c]->Clear( ); + + _frag_stats[c]->Clear( ); + + _sent_packets[c].assign(_nodes, 0); + _accepted_packets[c].assign(_nodes, 0); + _sent_flits[c].assign(_nodes, 0); + _accepted_flits[c].assign(_nodes, 0); + +#ifdef TRACK_STALLS + _buffer_busy_stalls[c].assign(_subnets*_routers, 0); + _buffer_conflict_stalls[c].assign(_subnets*_routers, 0); + _buffer_full_stalls[c].assign(_subnets*_routers, 0); + _buffer_reserved_stalls[c].assign(_subnets*_routers, 0); + _crossbar_conflict_stalls[c].assign(_subnets*_routers, 0); +#endif + if(_pair_stats){ + for ( int i = 0; i < _nodes; ++i ) { + for ( int j = 0; j < _nodes; ++j ) { + _pair_plat[c][i*_nodes+j]->Clear( ); + _pair_nlat[c][i*_nodes+j]->Clear( ); + _pair_flat[c][i*_nodes+j]->Clear( ); + } + } + } + _hop_stats[c]->Clear(); + + } + + _reset_time = _time; +} + +void TrafficManager::_ComputeStats( const vector<int> & stats, int *sum, int *min, int *max, int *min_pos, int *max_pos ) const +{ + int const count = stats.size(); + assert(count > 0); + + if(min_pos) { + *min_pos = 0; + } + if(max_pos) { + *max_pos = 0; + } + + if(min) { + *min = stats[0]; + } + if(max) { + *max = stats[0]; + } + + *sum = stats[0]; + + for ( int i = 1; i < count; ++i ) { + int curr = stats[i]; + if ( min && ( curr < *min ) ) { + *min = curr; + if ( min_pos ) { + *min_pos = i; + } + } + if ( max && ( curr > *max ) ) { + *max = curr; + if ( max_pos ) { + *max_pos = i; + } + } + *sum += curr; + } +} + +void TrafficManager::_DisplayRemaining( ostream & os ) const +{ + for(int c = 0; c < _classes; ++c) { + + map<int, Flit *>::const_iterator iter; + int i; + + os << "Class " << c << ":" << endl; + + os << "Remaining flits: "; + for ( iter = _total_in_flight_flits[c].begin( ), i = 0; + ( iter != _total_in_flight_flits[c].end( ) ) && ( i < 10 ); + iter++, i++ ) { + os << iter->first << " "; + } + if(_total_in_flight_flits[c].size() > 10) + os << "[...] "; + + os << "(" << _total_in_flight_flits[c].size() << " flits)" << endl; + + os << "Measured flits: "; + for ( iter = _measured_in_flight_flits[c].begin( ), i = 0; + ( iter != _measured_in_flight_flits[c].end( ) ) && ( i < 10 ); + iter++, i++ ) { + os << iter->first << " "; + } + if(_measured_in_flight_flits[c].size() > 10) + os << "[...] "; + + os << "(" << _measured_in_flight_flits[c].size() << " flits)" << endl; + + } +} + +bool TrafficManager::_SingleSim( ) +{ + int converged = 0; + + //once warmed up, we require 3 converging runs to end the simulation + vector<double> prev_latency(_classes, 0.0); + vector<double> prev_accepted(_classes, 0.0); + bool clear_last = false; + int total_phases = 0; + while( ( total_phases < _max_samples ) && + ( ( _sim_state != running ) || + ( converged < 3 ) ) ) { + + if ( clear_last || (( ( _sim_state == warming_up ) && ( ( total_phases % 2 ) == 0 ) )) ) { + clear_last = false; + _ClearStats( ); + } + + + for ( int iter = 0; iter < _sample_period; ++iter ) + _Step( ); + + //cout << _sim_state << endl; + + UpdateStats(); + DisplayStats(); + + int lat_exc_class = -1; + int lat_chg_exc_class = -1; + int acc_chg_exc_class = -1; + + for(int c = 0; c < _classes; ++c) { + + if(_measure_stats[c] == 0) { + continue; + } + + double cur_latency = _plat_stats[c]->Average( ); + + int total_accepted_count; + _ComputeStats( _accepted_flits[c], &total_accepted_count ); + double total_accepted_rate = (double)total_accepted_count / (double)(_time - _reset_time); + double cur_accepted = total_accepted_rate / (double)_nodes; + + double latency_change = fabs((cur_latency - prev_latency[c]) / cur_latency); + prev_latency[c] = cur_latency; + + double accepted_change = fabs((cur_accepted - prev_accepted[c]) / cur_accepted); + prev_accepted[c] = cur_accepted; + + double latency = (double)_plat_stats[c]->Sum(); + double count = (double)_plat_stats[c]->NumSamples(); + + map<int, Flit *>::const_iterator iter; + for(iter = _total_in_flight_flits[c].begin(); + iter != _total_in_flight_flits[c].end(); + iter++) { + latency += (double)(_time - iter->second->ctime); + count++; + } + + if((lat_exc_class < 0) && + (_latency_thres[c] >= 0.0) && + ((latency / count) > _latency_thres[c])) { + lat_exc_class = c; + } + + cout << "latency change = " << latency_change << endl; + if(lat_chg_exc_class < 0) { + if((_sim_state == warming_up) && + (_warmup_threshold[c] >= 0.0) && + (latency_change > _warmup_threshold[c])) { + lat_chg_exc_class = c; + } else if((_sim_state == running) && + (_stopping_threshold[c] >= 0.0) && + (latency_change > _stopping_threshold[c])) { + lat_chg_exc_class = c; + } + } + + cout << "throughput change = " << accepted_change << endl; + if(acc_chg_exc_class < 0) { + if((_sim_state == warming_up) && + (_acc_warmup_threshold[c] >= 0.0) && + (accepted_change > _acc_warmup_threshold[c])) { + acc_chg_exc_class = c; + } else if((_sim_state == running) && + (_acc_stopping_threshold[c] >= 0.0) && + (accepted_change > _acc_stopping_threshold[c])) { + acc_chg_exc_class = c; + } + } + + } + + // Fail safe for latency mode, throughput will ust continue + if ( _measure_latency && ( lat_exc_class >= 0 ) ) { + + cout << "Average latency for class " << lat_exc_class << " exceeded " << _latency_thres[lat_exc_class] << " cycles. Aborting simulation." << endl; + converged = 0; + _sim_state = draining; + _drain_time = _time; + if(_stats_out) { + WriteStats(*_stats_out); + } + break; + + } + + if ( _sim_state == warming_up ) { + if ( ( _warmup_periods > 0 ) ? + ( total_phases + 1 >= _warmup_periods ) : + ( ( !_measure_latency || ( lat_chg_exc_class < 0 ) ) && + ( acc_chg_exc_class < 0 ) ) ) { + cout << "Warmed up ..." << "Time used is " << _time << " cycles" <<endl; + clear_last = true; + _sim_state = running; + } + } else if(_sim_state == running) { + if ( ( !_measure_latency || ( lat_chg_exc_class < 0 ) ) && + ( acc_chg_exc_class < 0 ) ) { + ++converged; + } else { + converged = 0; + } + } + ++total_phases; + } + + if ( _sim_state == running ) { + ++converged; + + _sim_state = draining; + _drain_time = _time; + + if ( _measure_latency ) { + cout << "Draining all recorded packets ..." << endl; + int empty_steps = 0; + while( _PacketsOutstanding( ) ) { + _Step( ); + + ++empty_steps; + + if ( empty_steps % 1000 == 0 ) { + + int lat_exc_class = -1; + + for(int c = 0; c < _classes; c++) { + + double threshold = _latency_thres[c]; + + if(threshold < 0.0) { + continue; + } + + double acc_latency = _plat_stats[c]->Sum(); + double acc_count = (double)_plat_stats[c]->NumSamples(); + + map<int, Flit *>::const_iterator iter; + for(iter = _total_in_flight_flits[c].begin(); + iter != _total_in_flight_flits[c].end(); + iter++) { + acc_latency += (double)(_time - iter->second->ctime); + acc_count++; + } + + if((acc_latency / acc_count) > threshold) { + lat_exc_class = c; + break; + } + } + + if(lat_exc_class >= 0) { + cout << "Average latency for class " << lat_exc_class << " exceeded " << _latency_thres[lat_exc_class] << " cycles. Aborting simulation." << endl; + converged = 0; + _sim_state = warming_up; + if(_stats_out) { + WriteStats(*_stats_out); + } + break; + } + + _DisplayRemaining( ); + + } + } + } + } else { + cout << "Too many sample periods needed to converge" << endl; + } + + return ( converged > 0 ); +} + +bool TrafficManager::Run( ) +{ + for ( int sim = 0; sim < _total_sims; ++sim ) { + + _time = 0; + + //remove any pending request from the previous simulations + _requestsOutstanding.assign(_nodes, 0); + for (int i=0;i<_nodes;i++) { + while(!_repliesPending[i].empty()) { + _repliesPending[i].front()->Free(); + _repliesPending[i].pop_front(); + } + } + + //reset queuetime for all sources + for ( int s = 0; s < _nodes; ++s ) { + _qtime[s].assign(_classes, 0); + _qdrained[s].assign(_classes, false); + } + + // warm-up ... + // reset stats, all packets after warmup_time marked + // converge + // draing, wait until all packets finish + _sim_state = warming_up; + + _ClearStats( ); + + for(int c = 0; c < _classes; ++c) { + _traffic_pattern[c]->reset(); + _injection_process[c]->reset(); + } + + if ( !_SingleSim( ) ) { + cout << "Simulation unstable, ending ..." << endl; + return false; + } + + // Empty any remaining packets + cout << "Draining remaining packets ..." << endl; + _empty_network = true; + int empty_steps = 0; + + bool packets_left = false; + for(int c = 0; c < _classes; ++c) { + packets_left |= !_total_in_flight_flits[c].empty(); + } + + while( packets_left ) { + _Step( ); + + ++empty_steps; + + if ( empty_steps % 1000 == 0 ) { + _DisplayRemaining( ); + } + + packets_left = false; + for(int c = 0; c < _classes; ++c) { + packets_left |= !_total_in_flight_flits[c].empty(); + } + } + //wait until all the credits are drained as well + while(Credit::OutStanding()!=0){ + _Step(); + } + _empty_network = false; + + //for the love of god don't ever say "Time taken" anywhere else + //the power script depend on it + cout << "Time taken is " << _time << " cycles" <<endl; + + if(_stats_out) { + WriteStats(*_stats_out); + } + _UpdateOverallStats(); + } + + DisplayOverallStats(); + if(_print_csv_results) { + DisplayOverallStatsCSV(); + } + + return true; +} + +void TrafficManager::_UpdateOverallStats() { + for ( int c = 0; c < _classes; ++c ) { + + if(_measure_stats[c] == 0) { + continue; + } + + _overall_min_plat[c] += _plat_stats[c]->Min(); + _overall_avg_plat[c] += _plat_stats[c]->Average(); + _overall_max_plat[c] += _plat_stats[c]->Max(); + _overall_min_nlat[c] += _nlat_stats[c]->Min(); + _overall_avg_nlat[c] += _nlat_stats[c]->Average(); + _overall_max_nlat[c] += _nlat_stats[c]->Max(); + _overall_min_flat[c] += _flat_stats[c]->Min(); + _overall_avg_flat[c] += _flat_stats[c]->Average(); + _overall_max_flat[c] += _flat_stats[c]->Max(); + + _overall_min_frag[c] += _frag_stats[c]->Min(); + _overall_avg_frag[c] += _frag_stats[c]->Average(); + _overall_max_frag[c] += _frag_stats[c]->Max(); + + _overall_hop_stats[c] += _hop_stats[c]->Average(); + + int count_min, count_sum, count_max; + double rate_min, rate_sum, rate_max; + double rate_avg; + double time_delta = (double)(_drain_time - _reset_time); + _ComputeStats( _sent_flits[c], &count_sum, &count_min, &count_max ); + rate_min = (double)count_min / time_delta; + rate_sum = (double)count_sum / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + _overall_min_sent[c] += rate_min; + _overall_avg_sent[c] += rate_avg; + _overall_max_sent[c] += rate_max; + _ComputeStats( _sent_packets[c], &count_sum, &count_min, &count_max ); + rate_min = (double)count_min / time_delta; + rate_sum = (double)count_sum / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + _overall_min_sent_packets[c] += rate_min; + _overall_avg_sent_packets[c] += rate_avg; + _overall_max_sent_packets[c] += rate_max; + _ComputeStats( _accepted_flits[c], &count_sum, &count_min, &count_max ); + rate_min = (double)count_min / time_delta; + rate_sum = (double)count_sum / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + _overall_min_accepted[c] += rate_min; + _overall_avg_accepted[c] += rate_avg; + _overall_max_accepted[c] += rate_max; + _ComputeStats( _accepted_packets[c], &count_sum, &count_min, &count_max ); + rate_min = (double)count_min / time_delta; + rate_sum = (double)count_sum / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + _overall_min_accepted_packets[c] += rate_min; + _overall_avg_accepted_packets[c] += rate_avg; + _overall_max_accepted_packets[c] += rate_max; + +#ifdef TRACK_STALLS + _ComputeStats(_buffer_busy_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + _overall_buffer_busy_stalls[c] += rate_avg; + _ComputeStats(_buffer_conflict_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + _overall_buffer_conflict_stalls[c] += rate_avg; + _ComputeStats(_buffer_full_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + _overall_buffer_full_stalls[c] += rate_avg; + _ComputeStats(_buffer_reserved_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + _overall_buffer_reserved_stalls[c] += rate_avg; + _ComputeStats(_crossbar_conflict_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + _overall_crossbar_conflict_stalls[c] += rate_avg; +#endif + + } +} + +void TrafficManager::WriteStats(ostream & os) const { + + os << "%=================================" << endl; + + for(int c = 0; c < _classes; ++c) { + + if(_measure_stats[c] == 0) { + continue; + } + + //c+1 due to matlab array starting at 1 + os << "plat(" << c+1 << ") = " << _plat_stats[c]->Average() << ";" << endl + << "plat_hist(" << c+1 << ",:) = " << *_plat_stats[c] << ";" << endl + << "nlat(" << c+1 << ") = " << _nlat_stats[c]->Average() << ";" << endl + << "nlat_hist(" << c+1 << ",:) = " << *_nlat_stats[c] << ";" << endl + << "flat(" << c+1 << ") = " << _flat_stats[c]->Average() << ";" << endl + << "flat_hist(" << c+1 << ",:) = " << *_flat_stats[c] << ";" << endl + << "frag_hist(" << c+1 << ",:) = " << *_frag_stats[c] << ";" << endl + << "hops(" << c+1 << ",:) = " << *_hop_stats[c] << ";" << endl; + if(_pair_stats){ + os<< "pair_sent(" << c+1 << ",:) = [ "; + for(int i = 0; i < _nodes; ++i) { + for(int j = 0; j < _nodes; ++j) { + os << _pair_plat[c][i*_nodes+j]->NumSamples() << " "; + } + } + os << "];" << endl + << "pair_plat(" << c+1 << ",:) = [ "; + for(int i = 0; i < _nodes; ++i) { + for(int j = 0; j < _nodes; ++j) { + os << _pair_plat[c][i*_nodes+j]->Average( ) << " "; + } + } + os << "];" << endl + << "pair_nlat(" << c+1 << ",:) = [ "; + for(int i = 0; i < _nodes; ++i) { + for(int j = 0; j < _nodes; ++j) { + os << _pair_nlat[c][i*_nodes+j]->Average( ) << " "; + } + } + os << "];" << endl + << "pair_flat(" << c+1 << ",:) = [ "; + for(int i = 0; i < _nodes; ++i) { + for(int j = 0; j < _nodes; ++j) { + os << _pair_flat[c][i*_nodes+j]->Average( ) << " "; + } + } + } + + double time_delta = (double)(_drain_time - _reset_time); + + os << "];" << endl + << "sent_packets(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _nodes; ++d ) { + os << (double)_sent_packets[c][d] / time_delta << " "; + } + os << "];" << endl + << "accepted_packets(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _nodes; ++d ) { + os << (double)_accepted_packets[c][d] / time_delta << " "; + } + os << "];" << endl + << "sent_flits(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _nodes; ++d ) { + os << (double)_sent_flits[c][d] / time_delta << " "; + } + os << "];" << endl + << "accepted_flits(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _nodes; ++d ) { + os << (double)_accepted_flits[c][d] / time_delta << " "; + } + os << "];" << endl + << "sent_packet_size(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _nodes; ++d ) { + os << (double)_sent_flits[c][d] / (double)_sent_packets[c][d] << " "; + } + os << "];" << endl + << "accepted_packet_size(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _nodes; ++d ) { + os << (double)_accepted_flits[c][d] / (double)_accepted_packets[c][d] << " "; + } + os << "];" << endl; +#ifdef TRACK_STALLS + os << "buffer_busy_stalls(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _subnets*_routers; ++d ) { + os << (double)_buffer_busy_stalls[c][d] / time_delta << " "; + } + os << "];" << endl + << "buffer_conflict_stalls(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _subnets*_routers; ++d ) { + os << (double)_buffer_conflict_stalls[c][d] / time_delta << " "; + } + os << "];" << endl + << "buffer_full_stalls(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _subnets*_routers; ++d ) { + os << (double)_buffer_full_stalls[c][d] / time_delta << " "; + } + os << "];" << endl + << "buffer_reserved_stalls(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _subnets*_routers; ++d ) { + os << (double)_buffer_reserved_stalls[c][d] / time_delta << " "; + } + os << "];" << endl + << "crossbar_conflict_stalls(" << c+1 << ",:) = [ "; + for ( int d = 0; d < _subnets*_routers; ++d ) { + os << (double)_crossbar_conflict_stalls[c][d] / time_delta << " "; + } + os << "];" << endl; +#endif + } +} + +void TrafficManager::UpdateStats() { +#if defined(TRACK_FLOWS) || defined(TRACK_STALLS) + for(int c = 0; c < _classes; ++c) { +#ifdef TRACK_FLOWS + { + char trail_char = (c == _classes - 1) ? '\n' : ','; + if(_injected_flits_out) *_injected_flits_out << _injected_flits[c] << trail_char; + _injected_flits[c].assign(_nodes, 0); + if(_ejected_flits_out) *_ejected_flits_out << _ejected_flits[c] << trail_char; + _ejected_flits[c].assign(_nodes, 0); + } +#endif + for(int subnet = 0; subnet < _subnets; ++subnet) { +#ifdef TRACK_FLOWS + if(_outstanding_credits_out) *_outstanding_credits_out << _outstanding_credits[c][subnet] << ','; + if(_stored_flits_out) *_stored_flits_out << vector<int>(_nodes, 0) << ','; +#endif + for(int router = 0; router < _routers; ++router) { + Router * const r = _router[subnet][router]; +#ifdef TRACK_FLOWS + char trail_char = + ((router == _routers - 1) && (subnet == _subnets - 1) && (c == _classes - 1)) ? '\n' : ','; + if(_received_flits_out) *_received_flits_out << r->GetReceivedFlits(c) << trail_char; + if(_stored_flits_out) *_stored_flits_out << r->GetStoredFlits(c) << trail_char; + if(_sent_flits_out) *_sent_flits_out << r->GetSentFlits(c) << trail_char; + if(_outstanding_credits_out) *_outstanding_credits_out << r->GetOutstandingCredits(c) << trail_char; + if(_active_packets_out) *_active_packets_out << r->GetActivePackets(c) << trail_char; + r->ResetFlowStats(c); +#endif +#ifdef TRACK_STALLS + _buffer_busy_stalls[c][subnet*_routers+router] += r->GetBufferBusyStalls(c); + _buffer_conflict_stalls[c][subnet*_routers+router] += r->GetBufferConflictStalls(c); + _buffer_full_stalls[c][subnet*_routers+router] += r->GetBufferFullStalls(c); + _buffer_reserved_stalls[c][subnet*_routers+router] += r->GetBufferReservedStalls(c); + _crossbar_conflict_stalls[c][subnet*_routers+router] += r->GetCrossbarConflictStalls(c); + r->ResetStallStats(c); +#endif + } + } + } +#ifdef TRACK_FLOWS + if(_injected_flits_out) *_injected_flits_out << flush; + if(_received_flits_out) *_received_flits_out << flush; + if(_stored_flits_out) *_stored_flits_out << flush; + if(_sent_flits_out) *_sent_flits_out << flush; + if(_outstanding_credits_out) *_outstanding_credits_out << flush; + if(_ejected_flits_out) *_ejected_flits_out << flush; + if(_active_packets_out) *_active_packets_out << flush; +#endif +#endif + +#ifdef TRACK_CREDITS + for(int s = 0; s < _subnets; ++s) { + for(int n = 0; n < _nodes; ++n) { + BufferState const * const bs = _buf_states[n][s]; + for(int v = 0; v < _vcs; ++v) { + if(_used_credits_out) *_used_credits_out << bs->OccupancyFor(v) << ','; + if(_free_credits_out) *_free_credits_out << bs->AvailableFor(v) << ','; + if(_max_credits_out) *_max_credits_out << bs->LimitFor(v) << ','; + } + } + for(int r = 0; r < _routers; ++r) { + Router const * const rtr = _router[s][r]; + char trail_char = + ((r == _routers - 1) && (s == _subnets - 1)) ? '\n' : ','; + if(_used_credits_out) *_used_credits_out << rtr->UsedCredits() << trail_char; + if(_free_credits_out) *_free_credits_out << rtr->FreeCredits() << trail_char; + if(_max_credits_out) *_max_credits_out << rtr->MaxCredits() << trail_char; + } + } + if(_used_credits_out) *_used_credits_out << flush; + if(_free_credits_out) *_free_credits_out << flush; + if(_max_credits_out) *_max_credits_out << flush; +#endif + +} + +void TrafficManager::DisplayStats(ostream & os) const { + + for(int c = 0; c < _classes; ++c) { + + if(_measure_stats[c] == 0) { + continue; + } + + cout << "Class " << c << ":" << endl; + + cout + << "Packet latency average = " << _plat_stats[c]->Average() << endl + << "\tminimum = " << _plat_stats[c]->Min() << endl + << "\tmaximum = " << _plat_stats[c]->Max() << endl + << "Network latency average = " << _nlat_stats[c]->Average() << endl + << "\tminimum = " << _nlat_stats[c]->Min() << endl + << "\tmaximum = " << _nlat_stats[c]->Max() << endl + << "Slowest packet = " << _slowest_packet[c] << endl + << "Flit latency average = " << _flat_stats[c]->Average() << endl + << "\tminimum = " << _flat_stats[c]->Min() << endl + << "\tmaximum = " << _flat_stats[c]->Max() << endl + << "Slowest flit = " << _slowest_flit[c] << endl + << "Fragmentation average = " << _frag_stats[c]->Average() << endl + << "\tminimum = " << _frag_stats[c]->Min() << endl + << "\tmaximum = " << _frag_stats[c]->Max() << endl; + + int count_sum, count_min, count_max; + double rate_sum, rate_min, rate_max; + double rate_avg; + int sent_packets, sent_flits, accepted_packets, accepted_flits; + int min_pos, max_pos; + double time_delta = (double)(_time - _reset_time); + _ComputeStats(_sent_packets[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos); + rate_sum = (double)count_sum / time_delta; + rate_min = (double)count_min / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + sent_packets = count_sum; + cout << "Injected packet rate average = " << rate_avg << endl + << "\tminimum = " << rate_min + << " (at node " << min_pos << ")" << endl + << "\tmaximum = " << rate_max + << " (at node " << max_pos << ")" << endl; + _ComputeStats(_accepted_packets[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos); + rate_sum = (double)count_sum / time_delta; + rate_min = (double)count_min / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + accepted_packets = count_sum; + cout << "Accepted packet rate average = " << rate_avg << endl + << "\tminimum = " << rate_min + << " (at node " << min_pos << ")" << endl + << "\tmaximum = " << rate_max + << " (at node " << max_pos << ")" << endl; + _ComputeStats(_sent_flits[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos); + rate_sum = (double)count_sum / time_delta; + rate_min = (double)count_min / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + sent_flits = count_sum; + cout << "Injected flit rate average = " << rate_avg << endl + << "\tminimum = " << rate_min + << " (at node " << min_pos << ")" << endl + << "\tmaximum = " << rate_max + << " (at node " << max_pos << ")" << endl; + _ComputeStats(_accepted_flits[c], &count_sum, &count_min, &count_max, &min_pos, &max_pos); + rate_sum = (double)count_sum / time_delta; + rate_min = (double)count_min / time_delta; + rate_max = (double)count_max / time_delta; + rate_avg = rate_sum / (double)_nodes; + accepted_flits = count_sum; + cout << "Accepted flit rate average= " << rate_avg << endl + << "\tminimum = " << rate_min + << " (at node " << min_pos << ")" << endl + << "\tmaximum = " << rate_max + << " (at node " << max_pos << ")" << endl; + + cout << "Injected packet length average = " << (double)sent_flits / (double)sent_packets << endl + << "Accepted packet length average = " << (double)accepted_flits / (double)accepted_packets << endl; + + cout << "Total in-flight flits = " << _total_in_flight_flits[c].size() + << " (" << _measured_in_flight_flits[c].size() << " measured)" + << endl; + +#ifdef TRACK_STALLS + _ComputeStats(_buffer_busy_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + os << "Buffer busy stall rate = " << rate_avg << endl; + _ComputeStats(_buffer_conflict_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + os << "Buffer conflict stall rate = " << rate_avg << endl; + _ComputeStats(_buffer_full_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + os << "Buffer full stall rate = " << rate_avg << endl; + _ComputeStats(_buffer_reserved_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + os << "Buffer reserved stall rate = " << rate_avg << endl; + _ComputeStats(_crossbar_conflict_stalls[c], &count_sum); + rate_sum = (double)count_sum / time_delta; + rate_avg = rate_sum / (double)(_subnets*_routers); + os << "Crossbar conflict stall rate = " << rate_avg << endl; +#endif + + } +} + +void TrafficManager::DisplayOverallStats( ostream & os ) const { + + os << "====== Overall Traffic Statistics ======" << endl; + for ( int c = 0; c < _classes; ++c ) { + + if(_measure_stats[c] == 0) { + continue; + } + + os << "====== Traffic class " << c << " ======" << endl; + + os << "Packet latency average = " << _overall_avg_plat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_plat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_plat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Network latency average = " << _overall_avg_nlat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_nlat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_nlat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Flit latency average = " << _overall_avg_flat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_flat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_flat[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Fragmentation average = " << _overall_avg_frag[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_frag[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_frag[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Injected packet rate average = " << _overall_avg_sent_packets[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_sent_packets[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_sent_packets[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Accepted packet rate average = " << _overall_avg_accepted_packets[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_accepted_packets[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_accepted_packets[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Injected flit rate average = " << _overall_avg_sent[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_sent[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_sent[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Accepted flit rate average = " << _overall_avg_accepted[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tminimum = " << _overall_min_accepted[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + os << "\tmaximum = " << _overall_max_accepted[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + + os << "Injected packet size average = " << _overall_avg_sent[c] / _overall_avg_sent_packets[c] + << " (" << _total_sims << " samples)" << endl; + + os << "Accepted packet size average = " << _overall_avg_accepted[c] / _overall_avg_accepted_packets[c] + << " (" << _total_sims << " samples)" << endl; + + os << "Hops average = " << _overall_hop_stats[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; + +#ifdef TRACK_STALLS + os << "Buffer busy stall rate = " << (double)_overall_buffer_busy_stalls[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl + << "Buffer conflict stall rate = " << (double)_overall_buffer_conflict_stalls[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl + << "Buffer full stall rate = " << (double)_overall_buffer_full_stalls[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl + << "Buffer reserved stall rate = " << (double)_overall_buffer_reserved_stalls[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl + << "Crossbar conflict stall rate = " << (double)_overall_crossbar_conflict_stalls[c] / (double)_total_sims + << " (" << _total_sims << " samples)" << endl; +#endif + + } + +} + +string TrafficManager::_OverallStatsCSV(int c) const +{ + ostringstream os; + os << _traffic[c] + << ',' << _use_read_write[c] + << ',' << _load[c] + << ',' << _overall_min_plat[c] / (double)_total_sims + << ',' << _overall_avg_plat[c] / (double)_total_sims + << ',' << _overall_max_plat[c] / (double)_total_sims + << ',' << _overall_min_nlat[c] / (double)_total_sims + << ',' << _overall_avg_nlat[c] / (double)_total_sims + << ',' << _overall_max_nlat[c] / (double)_total_sims + << ',' << _overall_min_flat[c] / (double)_total_sims + << ',' << _overall_avg_flat[c] / (double)_total_sims + << ',' << _overall_max_flat[c] / (double)_total_sims + << ',' << _overall_min_frag[c] / (double)_total_sims + << ',' << _overall_avg_frag[c] / (double)_total_sims + << ',' << _overall_max_frag[c] / (double)_total_sims + << ',' << _overall_min_sent_packets[c] / (double)_total_sims + << ',' << _overall_avg_sent_packets[c] / (double)_total_sims + << ',' << _overall_max_sent_packets[c] / (double)_total_sims + << ',' << _overall_min_accepted_packets[c] / (double)_total_sims + << ',' << _overall_avg_accepted_packets[c] / (double)_total_sims + << ',' << _overall_max_accepted_packets[c] / (double)_total_sims + << ',' << _overall_min_sent[c] / (double)_total_sims + << ',' << _overall_avg_sent[c] / (double)_total_sims + << ',' << _overall_max_sent[c] / (double)_total_sims + << ',' << _overall_min_accepted[c] / (double)_total_sims + << ',' << _overall_avg_accepted[c] / (double)_total_sims + << ',' << _overall_max_accepted[c] / (double)_total_sims + << ',' << _overall_avg_sent[c] / _overall_avg_sent_packets[c] + << ',' << _overall_avg_accepted[c] / _overall_avg_accepted_packets[c] + << ',' << _overall_hop_stats[c] / (double)_total_sims; + +#ifdef TRACK_STALLS + os << ',' << (double)_overall_buffer_busy_stalls[c] / (double)_total_sims + << ',' << (double)_overall_buffer_conflict_stalls[c] / (double)_total_sims + << ',' << (double)_overall_buffer_full_stalls[c] / (double)_total_sims + << ',' << (double)_overall_buffer_reserved_stalls[c] / (double)_total_sims + << ',' << (double)_overall_crossbar_conflict_stalls[c] / (double)_total_sims; +#endif + + return os.str(); +} + +void TrafficManager::DisplayOverallStatsCSV(ostream & os) const { + for(int c = 0; c < _classes; ++c) { + os << "results:" << c << ',' << _OverallStatsCSV() << endl; + } +} + +//read the watchlist +void TrafficManager::_LoadWatchList(const string & filename){ + ifstream watch_list; + watch_list.open(filename.c_str()); + + string line; + if(watch_list.is_open()) { + while(!watch_list.eof()) { + getline(watch_list, line); + if(line != "") { + if(line[0] == 'p') { + _packets_to_watch.insert(atoi(line.c_str()+1)); + } else { + _flits_to_watch.insert(atoi(line.c_str())); + } + } + } + + } else { + Error("Unable to open flit watch file: " + filename); + } +} + +int TrafficManager::_GetNextPacketSize(int cl) const +{ + assert(cl >= 0 && cl < _classes); + + vector<int> const & psize = _packet_size[cl]; + int sizes = psize.size(); + + if(sizes == 1) { + return psize[0]; + } + + vector<int> const & prate = _packet_size_rate[cl]; + int max_val = _packet_size_max_val[cl]; + + int pct = RandomInt(max_val); + + for(int i = 0; i < (sizes - 1); ++i) { + int const limit = prate[i]; + if(limit > pct) { + return psize[i]; + } else { + pct -= limit; + } + } + assert(prate.back() > pct); + return psize.back(); +} + +double TrafficManager::_GetAveragePacketSize(int cl) const +{ + vector<int> const & psize = _packet_size[cl]; + int sizes = psize.size(); + if(sizes == 1) { + return (double)psize[0]; + } + vector<int> const & prate = _packet_size_rate[cl]; + int sum = 0; + for(int i = 0; i < sizes; ++i) { + sum += psize[i] * prate[i]; + } + return (double)sum / (double)(_packet_size_max_val[cl] + 1); +} diff --git a/src/intersim2/trafficmanager.hpp b/src/intersim2/trafficmanager.hpp new file mode 100644 index 0000000..9694df4 --- /dev/null +++ b/src/intersim2/trafficmanager.hpp @@ -0,0 +1,322 @@ +// $Id: trafficmanager.hpp 5365 2012-11-25 02:09:59Z qtedq $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _TRAFFICMANAGER_HPP_ +#define _TRAFFICMANAGER_HPP_ + +#include <list> +#include <map> +#include <set> +#include <cassert> + +#include "module.hpp" +#include "config_utils.hpp" +#include "network.hpp" +#include "flit.hpp" +#include "buffer_state.hpp" +#include "stats.hpp" +#include "traffic.hpp" +#include "routefunc.hpp" +#include "outputset.hpp" +#include "injection.hpp" + +//register the requests to a node +class PacketReplyInfo; + +class TrafficManager : public Module { + +private: + + vector<vector<int> > _packet_size; + vector<vector<int> > _packet_size_rate; + vector<int> _packet_size_max_val; + +protected: + int _nodes; + int _routers; + int _vcs; + + vector<Network *> _net; + vector<vector<Router *> > _router; + + // ============ Traffic ============ + + int _classes; + + vector<double> _load; + + vector<int> _use_read_write; + vector<double> _write_fraction; + + vector<int> _read_request_size; + vector<int> _read_reply_size; + vector<int> _write_request_size; + vector<int> _write_reply_size; + + vector<string> _traffic; + + vector<int> _class_priority; + + vector<vector<int> > _last_class; + + vector<TrafficPattern *> _traffic_pattern; + vector<InjectionProcess *> _injection_process; + + // ============ Message priorities ============ + + enum ePriority { class_based, age_based, network_age_based, local_age_based, queue_length_based, hop_count_based, sequence_based, none }; + + ePriority _pri_type; + + // ============ Injection VC states ============ + + vector<vector<BufferState *> > _buf_states; +#ifdef TRACK_FLOWS + vector<vector<vector<int> > > _outstanding_credits; + vector<vector<vector<queue<int> > > > _outstanding_classes; +#endif + vector<vector<vector<int> > > _last_vc; + + // ============ Routing ============ + + tRoutingFunction _rf; + bool _lookahead_routing; + bool _noq; + + // ============ Injection queues ============ + + vector<vector<int> > _qtime; + vector<vector<bool> > _qdrained; + vector<vector<list<Flit *> > > _partial_packets; + + vector<map<int, Flit *> > _total_in_flight_flits; + vector<map<int, Flit *> > _measured_in_flight_flits; + vector<map<int, Flit *> > _retired_packets; + bool _empty_network; + + bool _hold_switch_for_packet; + + // ============ physical sub-networks ========== + + int _subnets; + + vector<int> _subnet; + + // ============ deadlock ========== + + int _deadlock_timer; + int _deadlock_warn_timeout; + + // ============ request & replies ========================== + + vector<int> _packet_seq_no; + vector<list<PacketReplyInfo*> > _repliesPending; + vector<int> _requestsOutstanding; + + // ============ Statistics ============ + + vector<Stats *> _plat_stats; + vector<double> _overall_min_plat; + vector<double> _overall_avg_plat; + vector<double> _overall_max_plat; + + vector<Stats *> _nlat_stats; + vector<double> _overall_min_nlat; + vector<double> _overall_avg_nlat; + vector<double> _overall_max_nlat; + + vector<Stats *> _flat_stats; + vector<double> _overall_min_flat; + vector<double> _overall_avg_flat; + vector<double> _overall_max_flat; + + vector<Stats *> _frag_stats; + vector<double> _overall_min_frag; + vector<double> _overall_avg_frag; + vector<double> _overall_max_frag; + + vector<vector<Stats *> > _pair_plat; + vector<vector<Stats *> > _pair_nlat; + vector<vector<Stats *> > _pair_flat; + + vector<Stats *> _hop_stats; + vector<double> _overall_hop_stats; + + vector<vector<int> > _sent_packets; + vector<double> _overall_min_sent_packets; + vector<double> _overall_avg_sent_packets; + vector<double> _overall_max_sent_packets; + vector<vector<int> > _accepted_packets; + vector<double> _overall_min_accepted_packets; + vector<double> _overall_avg_accepted_packets; + vector<double> _overall_max_accepted_packets; + vector<vector<int> > _sent_flits; + vector<double> _overall_min_sent; + vector<double> _overall_avg_sent; + vector<double> _overall_max_sent; + vector<vector<int> > _accepted_flits; + vector<double> _overall_min_accepted; + vector<double> _overall_avg_accepted; + vector<double> _overall_max_accepted; + +#ifdef TRACK_STALLS + vector<vector<int> > _buffer_busy_stalls; + vector<vector<int> > _buffer_conflict_stalls; + vector<vector<int> > _buffer_full_stalls; + vector<vector<int> > _buffer_reserved_stalls; + vector<vector<int> > _crossbar_conflict_stalls; + vector<double> _overall_buffer_busy_stalls; + vector<double> _overall_buffer_conflict_stalls; + vector<double> _overall_buffer_full_stalls; + vector<double> _overall_buffer_reserved_stalls; + vector<double> _overall_crossbar_conflict_stalls; +#endif + + vector<int> _slowest_packet; + vector<int> _slowest_flit; + + map<string, Stats *> _stats; + + // ============ Simulation parameters ============ + + enum eSimState { warming_up, running, draining, done }; + eSimState _sim_state; + + bool _measure_latency; + + int _reset_time; + int _drain_time; + + int _total_sims; + int _sample_period; + int _max_samples; + int _warmup_periods; + + int _include_queuing; + + vector<int> _measure_stats; + bool _pair_stats; + + vector<double> _latency_thres; + + vector<double> _stopping_threshold; + vector<double> _acc_stopping_threshold; + + vector<double> _warmup_threshold; + vector<double> _acc_warmup_threshold; + + int _cur_id; + int _cur_pid; + int _time; + + set<int> _flits_to_watch; + set<int> _packets_to_watch; + + bool _print_csv_results; + + //flits to watch + ostream * _stats_out; + +#ifdef TRACK_FLOWS + vector<vector<int> > _injected_flits; + vector<vector<int> > _ejected_flits; + ostream * _injected_flits_out; + ostream * _received_flits_out; + ostream * _stored_flits_out; + ostream * _sent_flits_out; + ostream * _outstanding_credits_out; + ostream * _ejected_flits_out; + ostream * _active_packets_out; +#endif + +#ifdef TRACK_CREDITS + ostream * _used_credits_out; + ostream * _free_credits_out; + ostream * _max_credits_out; +#endif + + // ============ Internal methods ============ +protected: + + virtual void _RetireFlit( Flit *f, int dest ); + + void _Inject(); + virtual void _Step( ); + + bool _PacketsOutstanding( ) const; + + virtual int _IssuePacket( int source, int cl ); + virtual void _GeneratePacket( int source, int size, int cl, int time ); + + virtual void _ClearStats( ); + + void _ComputeStats( const vector<int> & stats, int *sum, int *min = NULL, int *max = NULL, int *min_pos = NULL, int *max_pos = NULL ) const; + + virtual bool _SingleSim( ); + + void _DisplayRemaining( ostream & os = cout ) const; + + void _LoadWatchList(const string & filename); + + virtual void _UpdateOverallStats(); + + virtual string _OverallStatsCSV(int c = 0) const; + + int _GetNextPacketSize(int cl) const; + double _GetAveragePacketSize(int cl) const; + +public: + + static TrafficManager * New(Configuration const & config, + vector<Network *> const & net); + + TrafficManager( const Configuration &config, const vector<Network *> & net ); + virtual ~TrafficManager( ); + + bool Run( ); + + virtual void WriteStats( ostream & os = cout ) const ; + virtual void UpdateStats( ) ; + virtual void DisplayStats( ostream & os = cout ) const ; + virtual void DisplayOverallStats( ostream & os = cout ) const ; + virtual void DisplayOverallStatsCSV( ostream & os = cout ) const ; + + inline int getTime() { return _time;} + Stats * getStats(const string & name) { return _stats[name]; } + +}; + +template<class T> +ostream & operator<<(ostream & os, const vector<T> & v) { + for(size_t i = 0; i < v.size() - 1; ++i) { + os << v[i] << ","; + } + os << v[v.size()-1]; + return os; +} + +#endif diff --git a/src/intersim2/vc.cpp b/src/intersim2/vc.cpp new file mode 100644 index 0000000..94e8c6b --- /dev/null +++ b/src/intersim2/vc.cpp @@ -0,0 +1,223 @@ +// $Id: vc.cpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +/*vc.cpp + * + *this class describes a virtual channel in a router + *it includes buffers and virtual channel state and controls + * + *This class calls the routing functions + */ + +#include <limits> +#include <sstream> + +#include "globals.hpp" +#include "booksim.hpp" +#include "vc.hpp" + +const char * const VC::VCSTATE[] = {"idle", + "routing", + "vc_alloc", + "active"}; + +VC::VC( const Configuration& config, int outputs, + Module *parent, const string& name ) + : Module( parent, name ), + _state(idle), _out_port(-1), _out_vc(-1), _pri(0), _watched(false), + _expected_pid(-1), _last_id(-1), _last_pid(-1) +{ + _lookahead_routing = !config.GetInt("routing_delay"); + _route_set = _lookahead_routing ? NULL : new OutputSet( ); + + string priority = config.GetStr( "priority" ); + if ( priority == "local_age" ) { + _pri_type = local_age_based; + } else if ( priority == "queue_length" ) { + _pri_type = queue_length_based; + } else if ( priority == "hop_count" ) { + _pri_type = hop_count_based; + } else if ( priority == "none" ) { + _pri_type = none; + } else { + _pri_type = other; + } + + _priority_donation = config.GetInt("vc_priority_donation"); +} + +VC::~VC() +{ + if(!_lookahead_routing) { + delete _route_set; + } +} + +void VC::AddFlit( Flit *f ) +{ + assert(f); + + if(_expected_pid >= 0) { + if(f->pid != _expected_pid) { + ostringstream err; + err << "Received flit " << f->id << " with unexpected packet ID: " << f->pid + << " (expected: " << _expected_pid << ")"; + Error(err.str()); + } else if(f->tail) { + _expected_pid = -1; + } + } else if(!f->tail) { + _expected_pid = f->pid; + } + + // update flit priority before adding to VC buffer + if(_pri_type == local_age_based) { + f->pri = numeric_limits<int>::max() - GetSimTime(); + assert(f->pri >= 0); + } else if(_pri_type == hop_count_based) { + f->pri = f->hops; + assert(f->pri >= 0); + } + + _buffer.push_back(f); + UpdatePriority(); +} + +Flit *VC::RemoveFlit( ) +{ + Flit *f = NULL; + if ( !_buffer.empty( ) ) { + f = _buffer.front( ); + _buffer.pop_front( ); + _last_id = f->id; + _last_pid = f->pid; + UpdatePriority(); + } else { + Error("Trying to remove flit from empty buffer."); + } + return f; +} + + + +void VC::SetState( eVCState s ) +{ + Flit * f = FrontFlit(); + + if(f && f->watch) + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Changing state from " << VC::VCSTATE[_state] + << " to " << VC::VCSTATE[s] << "." << endl; + + _state = s; +} + +const OutputSet *VC::GetRouteSet( ) const +{ + return _route_set; +} + +void VC::SetRouteSet( OutputSet * output_set ) +{ + _route_set = output_set; + _out_port = -1; + _out_vc = -1; +} + +void VC::SetOutput( int port, int vc ) +{ + _out_port = port; + _out_vc = vc; +} + +void VC::UpdatePriority() +{ + if(_buffer.empty()) return; + if(_pri_type == queue_length_based) { + _pri = _buffer.size(); + } else if(_pri_type != none) { + Flit * f = _buffer.front(); + if((_pri_type != local_age_based) && _priority_donation) { + Flit * df = f; + for(size_t i = 1; i < _buffer.size(); ++i) { + Flit * bf = _buffer[i]; + if(bf->pri > df->pri) df = bf; + } + if((df != f) && (df->watch || f->watch)) { + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Flit " << df->id + << " donates priority to flit " << f->id + << "." << endl; + } + f = df; + } + if(f->watch) + *gWatchOut << GetSimTime() << " | " << FullName() << " | " + << "Flit " << f->id + << " sets priority to " << f->pri + << "." << endl; + _pri = f->pri; + } +} + + +void VC::Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel ) +{ + rf( router, f, in_channel, _route_set, false ); + _out_port = -1; + _out_vc = -1; +} + +// ==== Debug functions ==== + +void VC::SetWatch( bool watch ) +{ + _watched = watch; +} + +bool VC::IsWatched( ) const +{ + return _watched; +} + +void VC::Display( ostream & os ) const +{ + if ( _state != VC::idle ) { + os << FullName() << ": " + << " state: " << VCSTATE[_state]; + if(_state == VC::active) { + os << " out_port: " << _out_port + << " out_vc: " << _out_vc; + } + os << " fill: " << _buffer.size(); + if(!_buffer.empty()) { + os << " front: " << _buffer.front()->id; + } + os << " pri: " << _pri; + os << endl; + } +} diff --git a/src/intersim2/vc.hpp b/src/intersim2/vc.hpp new file mode 100644 index 0000000..55ca317 --- /dev/null +++ b/src/intersim2/vc.hpp @@ -0,0 +1,137 @@ +// $Id: vc.hpp 5188 2012-08-30 00:31:31Z dub $ + +/* + Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University + All rights reserved. + + 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 following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 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 THE COPYRIGHT OWNER 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. +*/ + +#ifndef _VC_HPP_ +#define _VC_HPP_ + +#include <deque> + +#include "flit.hpp" +#include "outputset.hpp" +#include "routefunc.hpp" +#include "config_utils.hpp" + +class VC : public Module { +public: + enum eVCState { state_min = 0, idle = state_min, routing, vc_alloc, active, + state_max = active }; + struct state_info_t { + int cycles; + }; + static const char * const VCSTATE[]; + +private: + + deque<Flit *> _buffer; + + eVCState _state; + + OutputSet *_route_set; + int _out_port, _out_vc; + + enum ePrioType { local_age_based, queue_length_based, hop_count_based, none, other }; + + ePrioType _pri_type; + + int _pri; + + int _priority_donation; + + bool _watched; + + int _expected_pid; + + int _last_id; + int _last_pid; + + bool _lookahead_routing; + +public: + + VC( const Configuration& config, int outputs, + Module *parent, const string& name ); + ~VC(); + + void AddFlit( Flit *f ); + inline Flit *FrontFlit( ) const + { + return _buffer.empty() ? NULL : _buffer.front(); + } + + Flit *RemoveFlit( ); + + + inline bool Empty( ) const + { + return _buffer.empty( ); + } + + inline VC::eVCState GetState( ) const + { + return _state; + } + + + void SetState( eVCState s ); + + const OutputSet *GetRouteSet( ) const; + void SetRouteSet( OutputSet * output_set ); + + void SetOutput( int port, int vc ); + + inline int GetOutputPort( ) const + { + return _out_port; + } + + + inline int GetOutputVC( ) const + { + return _out_vc; + } + + void UpdatePriority(); + + inline int GetPriority( ) const + { + return _pri; + } + void Route( tRoutingFunction rf, const Router* router, const Flit* f, int in_channel ); + + inline int GetOccupancy() const + { + return (int)_buffer.size(); + } + + // ==== Debug functions ==== + + void SetWatch( bool watch = true ); + bool IsWatched( ) const; + void Display( ostream & os = cout ) const; +}; + +#endif diff --git a/src/statwrapper.cc b/src/statwrapper.cc new file mode 100644 index 0000000..e273e78 --- /dev/null +++ b/src/statwrapper.cc @@ -0,0 +1,59 @@ +//a Wraper function for stats class +#include "intersim2/stats.hpp" +#include <stdio.h> + +Stats* StatCreate (const char * name, double bin_size, int num_bins) { + Stats* newstat = new Stats(NULL,name,bin_size,num_bins); + newstat->Clear (); + return newstat; +} + +void StatClear(void * st) +{ + ((Stats *)st)->Clear(); +} + +void StatAddSample (void * st, int val) +{ + ((Stats *)st)->AddSample(val); +} + +double StatAverage(void * st) +{ + return((Stats *)st)->Average(); +} + +double StatMax(void * st) +{ + return((Stats *)st)->Max(); +} + +double StatMin(void * st) +{ + return((Stats *)st)->Min(); +} + +void StatDisp (void * st) +{ + printf ("Stats for "); + ((Stats *)st)->DisplayHierarchy(); +// if (((Stats *)st)->NeverUsed()) { +// printf (" was never updated!\n"); +// } else { + printf("Min %f Max %f Average %f \n",((Stats *)st)->Min(),((Stats *)st)->Max(),StatAverage(st)); + ((Stats *)st)->Display(); +// } +} + +#if 0 +int main () +{ + void * mytest = StatCreate("Test",1,5); + StatAddSample(mytest,4); + StatAddSample(mytest,4);StatAddSample(mytest,4); + StatAddSample(mytest,2); + StatDisp(mytest); +} +#endif + + diff --git a/src/statwrapper.h b/src/statwrapper.h new file mode 100644 index 0000000..65c2ab9 --- /dev/null +++ b/src/statwrapper.h @@ -0,0 +1,12 @@ +#ifndef STAT_WRAPER_H +#define STAT_WRAPER_H + +class Stats* StatCreate (const char * name, double bin_size, int num_bins) ; +void StatClear(void * st); +void StatAddSample (void * st, int val); +double StatAverage(void * st) ; +double StatMax(void * st) ; +double StatMin(void * st) ; +void StatDisp (void * st); + +#endif |
