diff options
| -rw-r--r-- | src/abstract_hardware_model.h | 29 | ||||
| -rw-r--r-- | src/cuda-sim/cuda-sim.cc | 18 | ||||
| -rw-r--r-- | src/cuda-sim/ptx.l | 3 | ||||
| -rw-r--r-- | src/cuda-sim/ptx.y | 9 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 175 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.h | 172 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 23 | ||||
| -rw-r--r-- | src/gpgpu-sim/icnt_wrapper.h | 3 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.cc | 9 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 110 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 51 | ||||
| -rw-r--r-- | src/intersim/interconnect_interface.cpp | 22 |
12 files changed, 459 insertions, 165 deletions
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index cdecc14..21f9689 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -408,11 +408,29 @@ enum mem_access_type { TEXTURE_ACC_R, GLOBAL_ACC_W, LOCAL_ACC_W, + L1_WRBK_ACC, L2_WRBK_ACC, - INST_ACC_R, + INST_ACC_R, NUM_MEM_ACCESS_TYPE }; +enum cache_operator_type { + CACHE_UNDEFINED, + + // loads + CACHE_ALL, // .ca + CACHE_LAST_USE, // .lu + CACHE_VOLATILE, // .cv + + // loads and stores + CACHE_STREAMING, // .cs + CACHE_GLOBAL, // .cg + + // stores + CACHE_WRITE_BACK, // .wb + CACHE_WRITE_THROUGH // .wt +}; + class mem_access_t { public: mem_access_t() { init(); } @@ -461,6 +479,7 @@ public: case LOCAL_ACC_W: fprintf(fp,"LOCAL_W "); break; case L2_WRBK_ACC: fprintf(fp,"L2_WRBK "); break; case INST_ACC_R: fprintf(fp,"INST "); break; + case L1_WRBK_ACC: fprintf(fp,"L1_WRBK "); break; default: fprintf(fp,"unknown "); break; } } @@ -492,6 +511,12 @@ public: virtual void push( mem_fetch *mf ) = 0; }; +class mem_fetch_allocator { +public: + virtual mem_fetch *alloc( new_addr_type addr, mem_access_type type, unsigned size, bool wr ) const = 0; + virtual mem_fetch *alloc( const class warp_inst_t &inst, const mem_access_t &access ) const = 0; +}; + #define MAX_REG_OPERANDS 8 struct dram_callback_t { @@ -513,6 +538,7 @@ public: is_vectorin=0; is_vectorout=0; space = memory_space_t(); + cache_op = CACHE_UNDEFINED; latency = 1; initiation_interval = 1; for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) @@ -544,6 +570,7 @@ public: unsigned data_size; // what is the size of the word being operated on? memory_space_t space; + cache_operator_type cache_op; protected: bool m_decoded; diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index b1893a0..34bfe82 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -566,6 +566,24 @@ void ptx_instruction::pre_decode() break; } + switch( m_cache_option ) { + case CA_OPTION: cache_op = CACHE_ALL; break; + case CG_OPTION: cache_op = CACHE_GLOBAL; break; + case CS_OPTION: cache_op = CACHE_STREAMING; break; + case LU_OPTION: cache_op = CACHE_LAST_USE; break; + case CV_OPTION: cache_op = CACHE_VOLATILE; break; + case WB_OPTION: cache_op = CACHE_WRITE_BACK; break; + case WT_OPTION: cache_op = CACHE_WRITE_THROUGH; break; + default: + if( m_opcode == LD_OP ) + cache_op = CACHE_ALL; + else if( m_opcode == ST_OP ) + cache_op = CACHE_WRITE_BACK; + else if( m_opcode == ATOM_OP ) + cache_op = CACHE_GLOBAL; + break; + } + set_opcode_and_latency(); // Get register operands diff --git a/src/cuda-sim/ptx.l b/src/cuda-sim/ptx.l index 1b87c7d..d54530d 100644 --- a/src/cuda-sim/ptx.l +++ b/src/cuda-sim/ptx.l @@ -340,6 +340,9 @@ breakaddr TC; ptx_lval.int_value = BREAKADDR_OP; return OPCODE; \.lu TC; return LU_OPTION; \.cv TC; return CV_OPTION; +\.wb TC; return WB_OPTION; +\.wt TC; return WT_OPTION; + \.and TC; return ATOMIC_AND; \.or TC; return ATOMIC_OR; \.xor TC; return ATOMIC_XOR; diff --git a/src/cuda-sim/ptx.y b/src/cuda-sim/ptx.y index 833e082..5142f4d 100644 --- a/src/cuda-sim/ptx.y +++ b/src/cuda-sim/ptx.y @@ -215,6 +215,8 @@ %token CS_OPTION; %token LU_OPTION; %token CV_OPTION; +%token WB_OPTION; +%token WT_OPTION; %type <int_value> function_decl_header %type <ptr_value> function_decl @@ -435,6 +437,13 @@ option: type_spec | atomic_operation_spec ; | TO_OPTION { add_option(TO_OPTION); } | HALF_OPTION { add_option(HALF_OPTION); } + | CA_OPTION { add_option(CA_OPTION); } + | CG_OPTION { add_option(CG_OPTION); } + | CS_OPTION { add_option(CS_OPTION); } + | LU_OPTION { add_option(LU_OPTION); } + | CV_OPTION { add_option(CV_OPTION); } + | WB_OPTION { add_option(WB_OPTION); } + | WT_OPTION { add_option(WT_OPTION); } ; atomic_operation_spec: ATOMIC_AND { add_option(ATOMIC_AND); } diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index c746da7..594e683 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -70,25 +70,24 @@ tag_array::~tag_array() { - delete m_lines; + delete m_lines; } tag_array::tag_array( const cache_config &config, int core_id, int type_id ) - : m_config(config) +: m_config(config) { - assert( m_config.m_write_policy == READ_ONLY ); - m_lines = new cache_block_t[ config.get_num_lines()]; + assert( m_config.m_write_policy == READ_ONLY ); + m_lines = new cache_block_t[ config.get_num_lines()]; - // initialize snapshot counters for visualizer - m_prev_snapshot_access = 0; - m_prev_snapshot_miss = 0; - m_prev_snapshot_pending_hit = 0; - m_core_id = core_id; - m_type_id = type_id; + // initialize snapshot counters for visualizer + m_prev_snapshot_access = 0; + m_prev_snapshot_miss = 0; + m_prev_snapshot_pending_hit = 0; + m_core_id = core_id; + m_type_id = type_id; } -enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx ) const -{ +enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx ) const { assert( m_config.m_write_policy == READ_ONLY ); unsigned set_index = m_config.set_index(addr); new_addr_type tag = m_config.tag(addr); @@ -98,57 +97,70 @@ enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx ) unsigned valid_timestamp = (unsigned)-1; bool all_reserved = true; - + // check for hit or pending hit for (unsigned way=0; way<m_config.m_assoc; way++) { - unsigned index = set_index*m_config.m_assoc+way; - cache_block_t *line = &m_lines[index]; - if (line->m_tag == tag) { - if( line->m_status == RESERVED ) { - idx = index; - return HIT_RESERVED; - } else if( line->m_status == VALID ) { - idx = index; - return HIT; - } else { - assert( line->m_status == INVALID ); - } - } - if(line->m_status != RESERVED) { - all_reserved = false; - if(line->m_status == INVALID) { - invalid_line = index; - } else { - // valid line : keep track of most appropriate replacement candidate - if( m_config.m_replacement_policy == LRU ) { - if( line->m_last_access_time < valid_timestamp ) { - valid_timestamp = line->m_last_access_time; - valid_line = index; - } - } else if( m_config.m_replacement_policy == FIFO ) { - if( line->m_alloc_time < valid_timestamp ) { - valid_timestamp = line->m_alloc_time; - valid_line = index; - } - } - } - } - } - if( all_reserved ) { - assert( m_config.m_alloc_policy == ON_MISS ); - return RESERVATION_FAIL; // miss and not enough space in cache to allocate on miss - } + unsigned index = set_index*m_config.m_assoc+way; + cache_block_t *line = &m_lines[index]; + if (line->m_tag == tag) { + if ( line->m_status == RESERVED ) { + idx = index; + return HIT_RESERVED; + } else if ( line->m_status == VALID ) { + idx = index; + return HIT; + } else if ( line->m_status == MODIFIED ) { + idx = index; + return HIT; + } else { + assert( line->m_status == INVALID ); + } + } + if (line->m_status != RESERVED) { + all_reserved = false; + if (line->m_status == INVALID) { + invalid_line = index; + } else { + // valid line : keep track of most appropriate replacement candidate + if ( m_config.m_replacement_policy == LRU ) { + if ( line->m_last_access_time < valid_timestamp ) { + valid_timestamp = line->m_last_access_time; + valid_line = index; + } + } else if ( m_config.m_replacement_policy == FIFO ) { + if ( line->m_alloc_time < valid_timestamp ) { + valid_timestamp = line->m_alloc_time; + valid_line = index; + } + } + } + } + } + if ( all_reserved ) { + assert( m_config.m_alloc_policy == ON_MISS ); + return RESERVATION_FAIL; // miss and not enough space in cache to allocate on miss + } - if( invalid_line != (unsigned)-1 ) { - idx = invalid_line; - } else if( valid_line != (unsigned)-1) { - idx = valid_line; - } else abort(); // if an unreserved block exists, it is either invalid or replaceable + if ( invalid_line != (unsigned)-1 ) { + idx = invalid_line; + } else if ( valid_line != (unsigned)-1) { + idx = valid_line; + } else abort(); // if an unreserved block exists, it is either invalid or replaceable - return MISS; + return MISS; } -enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx ) { +enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx ) +{ + bool wb=false; + cache_block_t evicted; + enum cache_request_status result = access(addr,time,idx,wb,evicted); + assert(!wb); + return result; +} + +enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx, bool &wb, cache_block_t &evicted ) +{ m_access++; shader_cache_access_log(m_core_id, m_type_id, 0); // log accesses to cache enum cache_request_status status = probe(addr,idx); @@ -161,8 +173,13 @@ enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, case MISS: m_miss++; shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses - if ( m_config.m_alloc_policy == ON_MISS ) + if ( m_config.m_alloc_policy == ON_MISS ) { + if( m_lines[idx].m_status == MODIFIED ) { + wb = true; + evicted = m_lines[idx]; + } m_lines[idx].allocate( m_config.tag(addr), m_config.block_addr(addr), time ); + } break; case RESERVATION_FAIL: m_miss++; @@ -190,37 +207,37 @@ void tag_array::fill( unsigned index, unsigned time ) void tag_array::flush() { - for (unsigned i=0; i < m_config.get_num_lines(); i++) - m_lines[i].m_status = INVALID; + for (unsigned i=0; i < m_config.get_num_lines(); i++) + m_lines[i].m_status = INVALID; } float tag_array::windowed_miss_rate( bool minus_pending_hit ) const { - unsigned n_access = m_access - m_prev_snapshot_access; - unsigned n_miss = m_miss - m_prev_snapshot_miss; - unsigned n_pending_hit = m_pending_hit - m_prev_snapshot_pending_hit; - - if (minus_pending_hit) - n_miss -= n_pending_hit; - float missrate = 0.0f; - if (n_access != 0) - missrate = (float) n_miss / n_access; - return missrate; + unsigned n_access = m_access - m_prev_snapshot_access; + unsigned n_miss = m_miss - m_prev_snapshot_miss; + unsigned n_pending_hit = m_pending_hit - m_prev_snapshot_pending_hit; + + if (minus_pending_hit) + n_miss -= n_pending_hit; + float missrate = 0.0f; + if (n_access != 0) + missrate = (float) n_miss / n_access; + return missrate; } void tag_array::new_window() { - m_prev_snapshot_access = m_access; - m_prev_snapshot_miss = m_miss; - m_prev_snapshot_pending_hit = m_pending_hit; + m_prev_snapshot_access = m_access; + m_prev_snapshot_miss = m_miss; + m_prev_snapshot_pending_hit = m_pending_hit; } void tag_array::print( FILE *stream, unsigned &total_access, unsigned &total_misses ) const { - m_config.print(stream); - fprintf( stream, "\t\tAccess = %d, Miss = %d (%.3g), -MgHts = %d (%.3g)\n", - m_access, m_miss, (float) m_miss / m_access, - m_miss - m_pending_hit, (float) (m_miss - m_pending_hit) / m_access); - total_misses+=m_miss; - total_access+=m_access; + m_config.print(stream); + fprintf( stream, "\t\tAccess = %d, Miss = %d (%.3g), -MgHts = %d (%.3g)\n", + m_access, m_miss, (float) m_miss / m_access, + m_miss - m_pending_hit, (float) (m_miss - m_pending_hit) / m_access); + total_misses+=m_miss; + total_access+=m_access; } diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index de85b8f..6b93d85 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -77,7 +77,8 @@ enum cache_block_state { INVALID, RESERVED, - VALID + VALID, + MODIFIED }; enum cache_request_status { @@ -147,6 +148,7 @@ public: cache_config() { m_valid = false; + m_disabled = false; m_config_string = NULL; // set by option parser } void init() @@ -156,8 +158,13 @@ public: int ntok = sscanf(m_config_string,"%u:%u:%u:%c:%c:%c,%c:%u:%u,%u:%u", &m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap, &mshr_type,&m_mshr_entries,&m_mshr_max_merge,&m_miss_queue_size,&m_result_fifo_entries); - if ( ntok < 10 ) + if ( ntok < 10 ) { + if ( !strcmp(m_config_string,"none") ) { + m_disabled = true; + return; + } exit_parse_error(); + } switch (rp) { case 'L': m_replacement_policy = LRU; break; case 'F': m_replacement_policy = FIFO; break; @@ -183,6 +190,7 @@ public: m_nset_log2 = LOGB2(m_nset); m_valid = true; } + bool disabled() const { return m_disabled;} unsigned get_line_sz() const { assert( m_valid ); @@ -224,6 +232,7 @@ private: } bool m_valid; + bool m_disabled; unsigned m_line_sz; unsigned m_line_sz_log2; unsigned m_nset; @@ -252,6 +261,7 @@ private: friend class tag_array; friend class read_only_cache; friend class tex_cache; + friend class data_cache; }; class tag_array { @@ -261,10 +271,14 @@ public: enum cache_request_status probe( new_addr_type addr, unsigned &idx ) const; enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx ); + enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx, bool &wb, cache_block_t &evicted ); void fill( new_addr_type addr, unsigned time ); void fill( unsigned idx, unsigned time ); + unsigned size() const { return m_config.get_num_lines();} + cache_block_t &get_block(unsigned idx) { return m_lines[idx];} + void flush(); // flash invalidate all entries void new_window(); @@ -408,12 +422,12 @@ public: { m_name = name; assert(config.m_mshr_type == ASSOC); - assert(config.m_write_policy == READ_ONLY); m_memport=memport; } // access cache: returns RESERVATION_FAIL if request could not be accepted (for any reason) virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) { + assert(m_config.m_write_policy == READ_ONLY); new_addr_type block_addr = m_config.block_addr(addr); unsigned cache_index = (unsigned)-1; enum cache_request_status status = m_tag_array.probe(block_addr,cache_index); @@ -499,7 +513,8 @@ public: fprintf(fp,"\n"); } -private: + + protected: std::string m_name; const cache_config &m_config; tag_array m_tag_array; @@ -521,13 +536,100 @@ private: unsigned m_cache_index; unsigned m_data_size; }; - + typedef std::map<mem_fetch*,extra_mf_fields> extra_mf_fields_lookup; extra_mf_fields_lookup m_extra_mf_fields; }; - +// This is meant to model the first level data cache in Fermi. +// It is write-evict (global) or write-back (local) at the granularity +// of individual blocks (the policy used in fermi according to the CUDA manual) + +class data_cache : public read_only_cache { +public: + data_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, mem_fetch_allocator *mfcreator ) + : read_only_cache(name,config,core_id,type_id,memport) + { + m_memfetch_creator=mfcreator; + } + virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) { + bool wr = mf->get_is_write(); + enum mem_access_type type = mf->get_access_type(); + bool evict = (type == GLOBAL_ACC_W); // evict a line that hits on global memory write + + new_addr_type block_addr = m_config.block_addr(addr); + unsigned cache_index = (unsigned)-1; + enum cache_request_status status = m_tag_array.probe(block_addr,cache_index); + if ( status == HIT ) { + if ( evict ) { + if ( m_miss_queue.size() >= m_config.m_miss_queue_size ) + return RESERVATION_FAIL; // cannot handle request this cycle + + // generate writeback request (this assumes we merge global write with this request) + // this does not ensure coherence since multiple writes to block could occcur at same + // time on different shader cores + cache_block_t &block = m_tag_array.get_block(cache_index); + mem_fetch *wb = m_memfetch_creator->alloc(block_addr,L1_WRBK_ACC,m_config.get_line_sz(),true); + m_miss_queue.push_back(wb); + + // invalidate block + block.m_status = INVALID; + } else { + m_tag_array.access(block_addr,time,cache_index); // update LRU state + if ( wr ) { + assert( type == LOCAL_ACC_W ); + // treated as write back... + cache_block_t &block = m_tag_array.get_block(cache_index); + block.m_status = MODIFIED; + } + } + return HIT; + } else if ( status != RESERVATION_FAIL ) { + if ( wr ) { + if ( m_miss_queue.size() >= m_config.m_miss_queue_size ) + return RESERVATION_FAIL; // cannot handle request this cycle + + // on miss, generate write through (no write buffering -- too many threads for that) + m_miss_queue.push_back(mf); + return MISS; + } else { + if ( (m_miss_queue.size()+1) >= m_config.m_miss_queue_size ) + return RESERVATION_FAIL; // cannot handle request this cycle (might need to generate two requests) + + bool do_miss = false; + bool wb = false; + cache_block_t evicted; + + bool mshr_hit = m_mshrs.probe(block_addr); + bool mshr_avail = !m_mshrs.full(block_addr); + if ( mshr_hit && mshr_avail ) { + m_tag_array.access(addr,time,cache_index,wb,evicted); + m_mshrs.add(block_addr,mf); + do_miss = true; + } else if ( !mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size) ) { + m_tag_array.access(addr,time,cache_index,wb,evicted); + m_mshrs.add(block_addr,mf); + m_extra_mf_fields[mf] = extra_mf_fields(block_addr,cache_index, mf->get_data_size()); + mf->set_data_size( m_config.get_line_sz() ); + m_miss_queue.push_back(mf); + do_miss = true; + } + if( wb ) { + mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,L1_WRBK_ACC,m_config.get_line_sz(),true); + m_miss_queue.push_back(wb); + } + if( do_miss ) + return MISS; + } + } + + return RESERVATION_FAIL; + } + private: + mem_fetch_allocator *m_memfetch_creator; +}; + // See the following paper to understand this cache model: // // Igehy, et al., Prefetching in a Texture Cache Architecture, @@ -537,11 +639,11 @@ class tex_cache : public cache_t { public: tex_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport ) : m_config(config), - m_tags(config,core_id,type_id), - m_fragment_fifo(config.m_fragment_fifo_entries), - m_request_fifo(config.m_request_fifo_entries), - m_rob(config.m_rob_entries), - m_result_fifo(config.m_result_fifo_entries) + m_tags(config,core_id,type_id), + m_fragment_fifo(config.m_fragment_fifo_entries), + m_request_fifo(config.m_request_fifo_entries), + m_rob(config.m_rob_entries), + m_result_fifo(config.m_result_fifo_entries) { m_name = name; assert(config.m_mshr_type == TEX_FIFO); @@ -555,11 +657,10 @@ public: // otherwise returns HIT_RESERVED or MISS; NOTE: *never* returns HIT // since unlike a normal CPU cache, a "HIT" in texture cache does not // mean the data is ready (still need to get through fragment fifo) - enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) - { - if( m_fragment_fifo.full() || m_request_fifo.full() || m_rob.full() ) + enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) { + if ( m_fragment_fifo.full() || m_request_fifo.full() || m_rob.full() ) return RESERVATION_FAIL; - + // at this point, we will accept the request : access tags and immediately allocate line new_addr_type block_addr = m_config.block_addr(addr); unsigned cache_index = (unsigned)-1; @@ -567,7 +668,7 @@ public: assert( status != RESERVATION_FAIL ); assert( status != HIT_RESERVED ); // as far as tags are concerned: HIT or MISS m_fragment_fifo.push( fragment_entry(mf,cache_index,status==MISS,mf->get_data_size()) ); - if( status == MISS ) { + if ( status == MISS ) { // we need to send a memory request... unsigned rob_index = m_rob.push( rob_entry(cache_index, mf, block_addr) ); m_extra_mf_fields[mf] = extra_mf_fields(rob_index); @@ -592,15 +693,15 @@ public: } } // read ready lines from cache - if( !m_fragment_fifo.empty() && !m_result_fifo.full() ) { + if ( !m_fragment_fifo.empty() && !m_result_fifo.full() ) { const fragment_entry &e = m_fragment_fifo.peek(); - if( e.m_miss ) { + if ( e.m_miss ) { // check head of reorder buffer to see if data is back from memory unsigned rob_index = m_rob.next_pop_index(); const rob_entry &r = m_rob.peek(rob_index); assert( r.m_request == e.m_request ); assert( r.m_block_addr == m_config.block_addr(e.m_request->get_addr()) ); - if( r.m_ready ) { + if ( r.m_ready ) { assert( r.m_index == e.m_cache_index ); m_cache[r.m_index].m_valid = true; m_cache[r.m_index].m_block_addr = r.m_block_addr; @@ -608,7 +709,7 @@ public: m_rob.pop(); m_fragment_fifo.pop(); } - } else { + } else { // hit: assert( m_cache[e.m_cache_index].m_valid ); assert( m_cache[e.m_cache_index].m_block_addr = m_config.block_addr(e.m_request->get_addr()) ); @@ -652,20 +753,20 @@ public: fprintf(fp,"fragment fifo entries = %u / %u\n", m_fragment_fifo.size(), m_fragment_fifo.capacity() ); fprintf(fp,"reorder buffer entries = %u / %u\n", m_rob.size(), m_rob.capacity() ); fprintf(fp,"request fifo entries = %u / %u\n", m_request_fifo.size(), m_request_fifo.capacity() ); - if( !m_rob.empty() ) + if ( !m_rob.empty() ) fprintf(fp,"reorder buffer contents:\n"); - for( int n=m_rob.size()-1; n>=0; n-- ) { + for ( int n=m_rob.size()-1; n>=0; n-- ) { unsigned index = (m_rob.next_pop_index() + n)%m_rob.capacity(); const rob_entry &r = m_rob.peek(index); fprintf(fp, "tex rob[%3d] : %s ", index, (r.m_ready?"ready ":"pending") ); - if( r.m_ready ) + if ( r.m_ready ) fprintf(fp,"@%6u", r.m_time ); - else + else fprintf(fp," "); fprintf(fp,"[idx=%4u]",r.m_index); r.m_request->print(fp,false); } - if( !m_fragment_fifo.empty() ) { + if ( !m_fragment_fifo.empty() ) { fprintf(fp,"fragment fifo (oldest) :"); fragment_entry &f = m_fragment_fifo.peek(); fprintf(fp,"%s: ", f.m_miss?"miss":"hit "); @@ -673,7 +774,8 @@ public: } } -private: + + private: std::string m_name; const cache_config &m_config; @@ -693,7 +795,7 @@ private: }; struct rob_entry { - rob_entry() { m_ready = false; m_time=0; m_request=NULL; } + rob_entry() { m_ready = false; m_time=0; m_request=NULL;} rob_entry( unsigned i, mem_fetch *mf, new_addr_type a ) { m_ready=false; @@ -710,7 +812,7 @@ private: }; struct data_block { - data_block() { m_valid = false; } + data_block() { m_valid = false;} bool m_valid; new_addr_type m_block_addr; }; @@ -726,10 +828,10 @@ private: m_tail=0; m_data = new T[size]; } - bool full() const { return m_num == m_size; } - bool empty() const { return m_num == 0; } - unsigned size() const { return m_num; } - unsigned capacity() const { return m_size; } + bool full() const { return m_num == m_size;} + bool empty() const { return m_num == 0;} + unsigned size() const { return m_num;} + unsigned capacity() const { return m_size;} unsigned push( const T &e ) { assert(!full()); @@ -764,8 +866,8 @@ private: return m_tail; } private: - void inc_head() { m_head = (m_head+1)%m_size; m_num++; } - void inc_tail() { assert(m_num>0); m_tail = (m_tail+1)%m_size; m_num--; } + void inc_head() { m_head = (m_head+1)%m_size; m_num++;} + void inc_tail() { assert(m_num>0); m_tail = (m_tail+1)%m_size; m_num--;} unsigned m_head; // next entry goes here unsigned m_tail; // oldest entry found here @@ -793,7 +895,7 @@ private: bool m_valid; unsigned m_rob_index; }; - + typedef std::map<mem_fetch*,extra_mf_fields> extra_mf_fields_lookup; extra_mf_fields_lookup m_extra_mf_fields; diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index fc93339..359a54d 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -136,7 +136,8 @@ void memory_config::reg_options(class OptionParser * opp) "Use a ideal L2 cache that always hit", "0"); option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &m_L2_config.m_config_string, - "unified banked L2 data cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}; disabled by default", + "unified banked L2 data cache config " + " {<nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>}", NULL); option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &m_n_mem, "number of memory modules (e.g. memory controllers) in gpu", @@ -174,11 +175,17 @@ void shader_core_config::reg_options(class OptionParser * opp) "per-shader L1 texture cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}", "512:64:2:L:R:m"); option_parser_register(opp, "-gpgpu_const_cache:l1", OPT_CSTR, &m_L1C_config.m_config_string, - "per-shader L1 constant memory cache (READ-ONLY) config, i.e., {<nsets>:<linesize>:<assoc>:<repl>|none}", - "64:64:2:L:R:f"); + "per-shader L1 constant memory cache (READ-ONLY) config " + " {<nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>}", + "64:64:2:L:R:f,A:2:32,4" ); option_parser_register(opp, "-gpgpu_cache:il1", OPT_CSTR, &m_L1I_config.m_config_string, - "shader L1 instruction cache config, i.e., {<nsets>:<bsize>:<assoc>:<repl>|none}", - "4:256:4:L:R:f"); + "shader L1 instruction cache config " + " {<nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>}", + "4:256:4:L:R:f,A:2:32,4" ); + option_parser_register(opp, "-gpgpu_cache:dl1", OPT_CSTR, &m_L1D_config.m_config_string, + "per-shader L1 data cache config " + " {<nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>|none}", + "none" ); option_parser_register(opp, "-gpgpu_perfect_mem", OPT_BOOL, &gpgpu_perfect_mem, "enable perfect memory mode (no cache miss)", "0"); @@ -501,7 +508,7 @@ unsigned int gpgpu_sim::run_gpu_sim() if (m_config.gpu_deadlock_detect && gpu_deadlock) { fflush(stdout); - printf("GPGPU-Sim uArch: ERROR ** deadlock detected: last writeback core %u @ gpu_sim_cycle %u (+ gpu_tot_sim_cycle %u) (%u cycles ago)\n", + printf("\n\nGPGPU-Sim uArch: ERROR ** deadlock detected: last writeback core %u @ gpu_sim_cycle %u (+ gpu_tot_sim_cycle %u) (%u cycles ago)\n", gpu_sim_insn_last_update_sid, (unsigned) gpu_sim_insn_last_update, (unsigned) (gpu_tot_sim_cycle-gpu_sim_cycle), (unsigned) (gpu_sim_cycle - gpu_sim_insn_last_update )); @@ -526,8 +533,10 @@ unsigned int gpgpu_sim::run_gpu_sim() if( busy ) printf("GPGPU-Sim uArch DEADLOCK: memory partition %u busy\n", i ); } - if( icnt_busy() ) + if( icnt_busy() ) { printf("GPGPU-Sim uArch DEADLOCK: iterconnect contains traffic\n"); + display_icnt_state( stdout ); + } printf("\nRe-run the simulator in gdb and use debug routines in .gdbinit to debug this\n"); fflush(stdout); abort(); diff --git a/src/gpgpu-sim/icnt_wrapper.h b/src/gpgpu-sim/icnt_wrapper.h index d37755a..b1ba991 100644 --- a/src/gpgpu-sim/icnt_wrapper.h +++ b/src/gpgpu-sim/icnt_wrapper.h @@ -67,6 +67,8 @@ #ifndef ICNT_WRAPPER_H #define ICNT_WRAPPER_H +#include <stdio.h> + // functional interface to the interconnect 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); @@ -90,5 +92,6 @@ enum network_mode { void icnt_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 45b8eef..ff09d18 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -283,8 +283,13 @@ void memory_partition_unit::dram_cycle() if ( !m_dram_L2_queue->full() ) { mem_fetch* mf = m_dram->pop(); if (mf) { - m_dram_L2_queue->push(mf); - mf->set_status(IN_PARTITION_DRAM_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + if( mf->get_access_type() == L1_WRBK_ACC ) { + m_request_tracker.erase(mf); + delete mf; + } else { + m_dram_L2_queue->push(mf); + mf->set_status(IN_PARTITION_DRAM_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + } } } m_dram->cycle(); diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 8adcf1b..303d736 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -136,15 +136,16 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, } m_icnt = new shader_memory_interface(this,cluster); + m_mem_fetch_allocator = new shader_core_mem_fetch_allocator(shader_id,tpc_id,mem_config); // fetch m_last_warp_fetched = 0; m_last_warp_issued = 0; #define STRSIZE 1024 - char L1I_name[STRSIZE]; - snprintf(L1I_name, STRSIZE, "L1I_%03d", m_sid); - m_L1I = new read_only_cache(L1I_name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id(),m_icnt); + char name[STRSIZE]; + snprintf(name, STRSIZE, "L1I_%03d", m_sid); + m_L1I = new read_only_cache( name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id(),m_icnt); m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size)); m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; @@ -178,7 +179,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_dispatch_port[1] = ID_OC_SFU; m_issue_port[1] = OC_EX_SFU; - m_ldst_unit = new ldst_unit( m_icnt, this, &m_operand_collector, m_scoreboard, config, mem_config, stats, shader_id, tpc_id ); + m_ldst_unit = new ldst_unit( m_icnt, m_mem_fetch_allocator, this, &m_operand_collector, m_scoreboard, config, mem_config, stats, shader_id, tpc_id ); m_fu[2] = m_ldst_unit; m_dispatch_port[2] = ID_OC_MEM; m_issue_port[2] = OC_EX_MEM; @@ -530,6 +531,9 @@ void shader_core_ctx::fetch() unsigned offset_in_block = pc & (m_config->m_L1I_config.get_line_sz()-1); if( (offset_in_block+nbytes) > m_config->m_L1I_config.get_line_sz() ) nbytes = (m_config->m_L1I_config.get_line_sz()-offset_in_block); + + // TODO: replace with use of allocator + // mem_fetch *mf = m_mem_fetch_allocator->alloc() mem_access_t acc(INST_ACC_R,ppc,nbytes,false); mem_fetch *mf = new mem_fetch(acc, NULL/*we don't have an instruction yet*/, @@ -734,20 +738,6 @@ void shader_core_ctx::execute() } } -mem_fetch *ldst_unit::create_data_mem_fetch(const warp_inst_t &inst, const mem_access_t &access) -{ - warp_inst_t inst_copy = inst; - inst_copy.set_active(access.get_warp_mask()); - mem_fetch *mf = new mem_fetch(access, - &inst_copy, - access.is_write()?WRITE_PACKET_SIZE:READ_PACKET_SIZE, - inst.warp_id(), - m_sid, - m_tpc, - m_memory_config); - return mf; -} - void shader_core_ctx::writeback() { warp_inst_t *&pipe_reg = m_pipeline_reg[EX_WB]; @@ -784,7 +774,7 @@ mem_stage_stall_type ldst_unit::process_memory_access_queue( cache_t *cache, war return result; const mem_access_t &access = inst.accessq_back(); - mem_fetch *mf = create_data_mem_fetch(inst,inst.accessq_back()); + mem_fetch *mf = m_mf_allocator->alloc(inst,inst.accessq_back()); enum cache_request_status status = cache->access(mf->get_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle); if ( status == HIT ) { @@ -801,7 +791,8 @@ mem_stage_stall_type ldst_unit::process_memory_access_queue( cache_t *cache, war for ( unsigned r=0; r < 4; r++) if (inst.out[r] > 0) m_pending_writes[inst.warp_id()][inst.out[r]]++; - } + } else if( inst.is_store() ) + m_core->inc_store_req( inst.warp_id() ); } if( !inst.accessq_empty() ) result = BK_CONF; @@ -852,19 +843,27 @@ bool ldst_unit::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_rea mem_stage_stall_type stall_cond = NO_RC_FAIL; const mem_access_t &access = inst.accessq_back(); unsigned size = access.get_size(); - if( m_icnt->full(size, inst.is_store()) ) { - stall_cond = ICNT_RC_FAIL; + + assert( CACHE_UNDEFINED != inst.cache_op ); + + if( CACHE_GLOBAL == inst.cache_op || (m_L1D == NULL) ) { + // bypass L1 cache + if( m_icnt->full(size, inst.is_store()) ) { + stall_cond = ICNT_RC_FAIL; + } else { + mem_fetch *mf = m_mf_allocator->alloc(inst,access); + m_icnt->push(mf); + inst.accessq_pop_back(); + inst.clear_active( access.get_warp_mask() ); + if( inst.is_load() ) { + for( unsigned r=0; r < 4; r++) + if(inst.out[r] > 0) + m_pending_writes[inst.warp_id()][inst.out[r]]++; + } else if( inst.is_store() ) + m_core->inc_store_req( inst.warp_id() ); + } } else { - mem_fetch *mf = create_data_mem_fetch(inst,access); - m_icnt->push(mf); - inst.accessq_pop_back(); - inst.clear_active( access.get_warp_mask() ); - if( inst.is_load() ) { - for( unsigned r=0; r < 4; r++) - if(inst.out[r] > 0) - m_pending_writes[inst.warp_id()][inst.out[r]]++; - } else if( inst.is_store() ) - m_core->inc_store_req( inst.warp_id() ); + stall_cond = process_memory_access_queue(m_L1D,inst); } if( !inst.accessq_empty() ) stall_cond = COAL_STALL; @@ -926,6 +925,7 @@ pipelined_simd_unit::pipelined_simd_unit( warp_inst_t **result_port, const shade } ldst_unit::ldst_unit( shader_memory_interface *icnt, + shader_core_mem_fetch_allocator *mf_allocator, shader_core_ctx *core, opndcoll_rfu_t *operand_collector, Scoreboard *scoreboard, @@ -935,8 +935,9 @@ ldst_unit::ldst_unit( shader_memory_interface *icnt, unsigned sid, unsigned tpc ) : pipelined_simd_unit(NULL,config,3), m_next_wb(config) { - m_memory_config = mem_config; + m_memory_config = mem_config; m_icnt = icnt; + m_mf_allocator=mf_allocator; m_core = core; m_operand_collector = operand_collector; m_scoreboard = scoreboard; @@ -946,12 +947,17 @@ ldst_unit::ldst_unit( shader_memory_interface *icnt, #define STRSIZE 1024 char L1T_name[STRSIZE]; char L1C_name[STRSIZE]; + char L1D_name[STRSIZE]; snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid); snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid); + snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid); m_L1T = new tex_cache(L1T_name,m_config->m_L1T_config,m_sid,get_shader_texture_cache_id(),icnt); m_L1C = new read_only_cache(L1C_name,m_config->m_L1C_config,m_sid,get_shader_constant_cache_id(),icnt); + m_L1D = NULL; + if( !m_config->m_L1D_config.disabled() ) + m_L1D = new data_cache(L1D_name,m_config->m_L1D_config,m_sid,get_shader_normal_cache_id(),m_icnt,m_mf_allocator); m_mem_rc = NO_RC_FAIL; - m_num_writeback_clients=4; // = shared memory, global/local, L1T, L1C + m_num_writeback_clients=5; // = shared memory, global/local (uncached), L1D, L1T, L1C m_writeback_arb = 0; m_next_global=NULL; } @@ -1014,6 +1020,13 @@ void ldst_unit::writeback() m_next_global = NULL; } break; + case 4: + if( m_L1D && m_L1D->access_ready() ) { + mem_fetch *mf = m_L1D->next_access(); + m_next_wb = mf->get_inst(); + delete mf; + } + break; default: abort(); } } @@ -1046,7 +1059,10 @@ void ldst_unit::cycle() m_response_fifo.pop_front(); delete mf; } else { - if( m_next_global == NULL ) { + if( mf->get_inst().cache_op != CACHE_GLOBAL && m_L1D ) { + m_L1D->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + } else if( m_next_global == NULL ) { mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); m_response_fifo.pop_front(); m_next_global = mf; @@ -1057,6 +1073,7 @@ void ldst_unit::cycle() m_L1T->cycle(); m_L1C->cycle(); + if( m_L1D ) m_L1D->cycle(); warp_inst_t &pipe_reg = *m_dispatch_reg; enum mem_stage_stall_type rc_fail = NO_RC_FAIL; @@ -1084,10 +1101,10 @@ void ldst_unit::cycle() m_dispatch_reg->clear(); } } else { - if( pipe_reg.active_count() > 0 ) { - if( !m_operand_collector->writeback(pipe_reg) ) - return; - } + //if( pipe_reg.active_count() > 0 ) { + // if( !m_operand_collector->writeback(pipe_reg) ) + // return; + //} bool pending_requests=false; for( unsigned r=0; r<4; r++ ) { @@ -1293,6 +1310,12 @@ void ldst_unit::print(FILE *fout) const } m_L1C->display_state(fout); m_L1T->display_state(fout); + m_L1D->display_state(fout); + fprintf(fout,"LD/ST response FIFO (occupancy = %zu):\n", m_response_fifo.size() ); + for( std::list<mem_fetch*>::const_iterator i=m_response_fifo.begin(); i != m_response_fifo.end(); i++ ) { + const mem_fetch *mf = *i; + mf->print(fout); + } } void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) const @@ -2050,6 +2073,7 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf) case LOCAL_ACC_R: m_stats->gpgpu_n_mem_read_local++; break; case LOCAL_ACC_W: m_stats->gpgpu_n_mem_write_local++; break; case INST_ACC_R: m_stats->gpgpu_n_mem_read_inst++; break; + case L1_WRBK_ACC: m_stats->gpgpu_n_mem_write_global++; break; default: assert(0); } unsigned destination = mf->get_tlx_addr().chip; @@ -2101,4 +2125,12 @@ void simt_core_cluster::get_pdom_stack_top_info( unsigned sid, unsigned tid, uns void simt_core_cluster::display_pipeline( unsigned sid, FILE *fout, int print_mem, int mask ) { m_core[m_config->sid_to_cid(sid)]->display_pipeline(fout,print_mem,mask); + + fprintf(fout,"\n"); + fprintf(fout,"Cluster %u pipeline state\n", m_cluster_id ); + fprintf(fout,"Response FIFO (occupancy = %zu):\n", m_response_fifo.size() ); + for( std::list<mem_fetch*>::const_iterator i=m_response_fifo.begin(); i != m_response_fifo.end(); i++ ) { + const mem_fetch *mf = *i; + mf->print(fout); + } } diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index e85c210..bfe0cc2 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -831,11 +831,13 @@ public: class simt_core_cluster; class shader_memory_interface; +class shader_core_mem_fetch_allocator; class cache_t; class ldst_unit: public pipelined_simd_unit { public: ldst_unit( shader_memory_interface *icnt, + shader_core_mem_fetch_allocator *mf_allocator, shader_core_ctx *core, opndcoll_rfu_t *operand_collector, Scoreboard *scoreboard, @@ -875,16 +877,17 @@ private: bool memory_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); mem_stage_stall_type process_memory_access_queue( cache_t *cache, warp_inst_t &inst ); - mem_fetch *create_data_mem_fetch(const warp_inst_t &inst, const mem_access_t &access); const memory_config *m_memory_config; - class shader_memory_interface *m_icnt; + shader_memory_interface *m_icnt; + shader_core_mem_fetch_allocator *m_mf_allocator; class shader_core_ctx *m_core; unsigned m_sid; unsigned m_tpc; tex_cache *m_L1T; // texture cache read_only_cache *m_L1C; // constant cache + data_cache *m_L1D; // data cache std::map<unsigned/*warp_id*/, std::map<unsigned/*regnum*/,unsigned/*count*/> > m_pending_writes; std::list<mem_fetch*> m_response_fifo; opndcoll_rfu_t *m_operand_collector; @@ -929,6 +932,7 @@ struct shader_core_config : public core_config m_L1I_config.init(); m_L1T_config.init(); m_L1C_config.init(); + m_L1D_config.init(); gpgpu_cache_texl1_linesize = m_L1T_config.get_line_sz(); gpgpu_cache_constl1_linesize = m_L1C_config.get_line_sz(); m_valid = true; @@ -951,6 +955,7 @@ struct shader_core_config : public core_config cache_config m_L1I_config; cache_config m_L1T_config; cache_config m_L1C_config; + cache_config m_L1D_config; bool gpgpu_dwf_reg_bankconflict; int gpgpu_operand_collector_num_units_sp; @@ -1039,6 +1044,47 @@ private: friend class simt_core_cluster; }; +class shader_core_mem_fetch_allocator : public mem_fetch_allocator { +public: + shader_core_mem_fetch_allocator( unsigned core_id, unsigned cluster_id, const memory_config *config ) + { + m_core_id = core_id; + m_cluster_id = cluster_id; + m_memory_config = config; + } + mem_fetch *alloc( new_addr_type addr, mem_access_type type, unsigned size, bool wr ) const + { + mem_access_t access( type, addr, size, wr ); + mem_fetch *mf = new mem_fetch( access, + NULL, + wr?WRITE_PACKET_SIZE:READ_PACKET_SIZE, + -1, + m_core_id, + m_cluster_id, + m_memory_config ); + return mf; + } + + mem_fetch *alloc( const warp_inst_t &inst, const mem_access_t &access ) const + { + warp_inst_t inst_copy = inst; + inst_copy.set_active(access.get_warp_mask()); + mem_fetch *mf = new mem_fetch(access, + &inst_copy, + access.is_write()?WRITE_PACKET_SIZE:READ_PACKET_SIZE, + inst.warp_id(), + m_core_id, + m_cluster_id, + m_memory_config); + return mf; + } + +private: + unsigned m_core_id; + unsigned m_cluster_id; + const memory_config *m_memory_config; +}; + class shader_core_ctx : public core_t { public: // creator: @@ -1135,6 +1181,7 @@ private: // interconnect interface shader_memory_interface *m_icnt; + shader_core_mem_fetch_allocator *m_mem_fetch_allocator; // fetch read_only_cache *m_L1I; // instruction cache diff --git a/src/intersim/interconnect_interface.cpp b/src/intersim/interconnect_interface.cpp index 3059b44..0c155f1 100644 --- a/src/intersim/interconnect_interface.cpp +++ b/src/intersim/interconnect_interface.cpp @@ -512,6 +512,28 @@ unsigned interconnect_busy() return 0; } +void display_icnt_state( FILE *fp ) +{ + 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 ); + } + } +} + //create buffers for src_n nodes void create_buf(int src_n,int warp_n,int vc_n) { |
