diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 160 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.h | 81 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 1 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.cc | 24 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 32 | ||||
| -rw-r--r-- | src/gpgpu-sim/stats.h | 1 |
6 files changed, 264 insertions, 35 deletions
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index 4c5c5c9..f927e9a 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -281,6 +281,15 @@ bool was_write_sent( const std::list<cache_event> &events ) return false; } +bool was_writeback_sent( const std::list<cache_event> &events ) +{ + for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) { + if( *e == WRITE_BACK_REQUEST_SENT ) + return true; + } + return false; +} + bool was_read_sent( const std::list<cache_event> &events ) { for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) { @@ -362,6 +371,9 @@ cache_stats::cache_stats(){ for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){ m_stats[i].resize(NUM_CACHE_REQUEST_STATUS, 0); } + m_cache_port_available_cycles = 0; + m_cache_data_port_busy_cycles = 0; + m_cache_fill_port_busy_cycles = 0; } void cache_stats::clear(){ @@ -371,6 +383,9 @@ void cache_stats::clear(){ for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){ std::fill(m_stats[i].begin(), m_stats[i].end(), 0); } + m_cache_port_available_cycles = 0; + m_cache_data_port_busy_cycles = 0; + m_cache_fill_port_busy_cycles = 0; } void cache_stats::inc_stats(int access_type, int access_outcome){ @@ -425,6 +440,9 @@ cache_stats cache_stats::operator+(const cache_stats &cs){ ret(type, status) = m_stats[type][status] + cs(type, status); } } + ret.m_cache_port_available_cycles = m_cache_port_available_cycles + cs.m_cache_port_available_cycles; + ret.m_cache_data_port_busy_cycles = m_cache_data_port_busy_cycles + cs.m_cache_data_port_busy_cycles; + ret.m_cache_fill_port_busy_cycles = m_cache_fill_port_busy_cycles + cs.m_cache_fill_port_busy_cycles; return ret; } @@ -437,6 +455,9 @@ cache_stats &cache_stats::operator+=(const cache_stats &cs){ m_stats[type][status] += cs(type, status); } } + m_cache_port_available_cycles += cs.m_cache_port_available_cycles; + m_cache_data_port_busy_cycles += cs.m_cache_data_port_busy_cycles; + m_cache_fill_port_busy_cycles += cs.m_cache_fill_port_busy_cycles; return *this; } @@ -461,6 +482,20 @@ void cache_stats::print_stats(FILE *fout, const char *cache_name) const{ } } +void cache_sub_stats::print_port_stats(FILE *fout, const char *cache_name) const +{ + float data_port_util = 0.0f; + if (port_available_cycles > 0) { + data_port_util = (float) data_port_busy_cycles / port_available_cycles; + } + fprintf(fout, "%s_data_port_util = %.3f\n", cache_name, data_port_util); + float fill_port_util = 0.0f; + if (port_available_cycles > 0) { + fill_port_util = (float) fill_port_busy_cycles / port_available_cycles; + } + fprintf(fout, "%s_fill_port_util = %.3f\n", cache_name, fill_port_util); +} + unsigned cache_stats::get_stats(enum mem_access_type *access_type, unsigned num_access_type, enum cache_request_status *access_status, unsigned num_access_status) const{ /// /// Returns a sum of the stats corresponding to each "access_type" and "access_status" pair. @@ -499,6 +534,11 @@ void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{ t_css.res_fails += m_stats[type][status]; } } + + t_css.port_available_cycles = m_cache_port_available_cycles; + t_css.data_port_busy_cycles = m_cache_data_port_busy_cycles; + t_css.fill_port_busy_cycles = m_cache_fill_port_busy_cycles; + css = t_css; } @@ -512,6 +552,85 @@ bool cache_stats::check_valid(int type, int status) const{ return false; } +void cache_stats::sample_cache_port_utility(bool data_port_busy, bool fill_port_busy) +{ + m_cache_port_available_cycles += 1; + if (data_port_busy) { + m_cache_data_port_busy_cycles += 1; + } + if (fill_port_busy) { + m_cache_fill_port_busy_cycles += 1; + } +} + +baseline_cache::bandwidth_management::bandwidth_management(cache_config &config) +: m_config(config) +{ + m_data_port_occupied_cycles = 0; + m_fill_port_occupied_cycles = 0; +} + +/// use the data port based on the outcome and events generated by the mem_fetch request +void baseline_cache::bandwidth_management::use_data_port(mem_fetch *mf, enum cache_request_status outcome, const std::list<cache_event> &events) +{ + unsigned data_size = mf->get_data_size(); + unsigned port_width = m_config.m_data_port_width; + switch (outcome) { + case HIT: { + unsigned data_cycles = data_size / port_width + ((data_size % port_width > 0)? 1 : 0); + m_data_port_occupied_cycles += data_cycles; + } break; + case HIT_RESERVED: + case MISS: { + // the data array is accessed to read out the entire line for write-back + if (was_writeback_sent(events)) { + unsigned data_cycles = m_config.m_line_sz / port_width; + m_data_port_occupied_cycles += data_cycles; + } + } break; + case RESERVATION_FAIL: + // Does not consume any port bandwidth + break; + default: + assert(0); + break; + } +} + +/// use the fill port +void baseline_cache::bandwidth_management::use_fill_port(mem_fetch *mf) +{ + // assume filling the entire line with the returned request + unsigned fill_cycles = m_config.m_line_sz / m_config.m_data_port_width; + m_fill_port_occupied_cycles += fill_cycles; +} + +/// called every cache cycle to free up the ports +void baseline_cache::bandwidth_management::replenish_port_bandwidth() +{ + if (m_data_port_occupied_cycles > 0) { + m_data_port_occupied_cycles -= 1; + } + assert(m_data_port_occupied_cycles >= 0); + + if (m_fill_port_occupied_cycles > 0) { + m_fill_port_occupied_cycles -= 1; + } + assert(m_fill_port_occupied_cycles >= 0); +} + +/// query for data port availability +bool baseline_cache::bandwidth_management::data_port_free() const +{ + return (m_data_port_occupied_cycles == 0); +} + +/// query for fill port availability +bool baseline_cache::bandwidth_management::fill_port_free() const +{ + return (m_fill_port_occupied_cycles == 0); +} + /// Sends next request to lower level of memory void baseline_cache::cycle(){ if ( !m_miss_queue.empty() ) { @@ -521,27 +640,32 @@ void baseline_cache::cycle(){ m_memport->push(mf); } } + bool data_port_busy = !m_bandwidth_management.data_port_free(); + bool fill_port_busy = !m_bandwidth_management.fill_port_free(); + m_stats.sample_cache_port_utility(data_port_busy, fill_port_busy); + m_bandwidth_management.replenish_port_bandwidth(); } /// Interface for response from lower memory level (model bandwidth restictions in caller) void baseline_cache::fill(mem_fetch *mf, unsigned time){ - extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf); - assert( e != m_extra_mf_fields.end() ); - assert( e->second.m_valid ); - mf->set_data_size( e->second.m_data_size ); - if ( m_config.m_alloc_policy == ON_MISS ) - m_tag_array->fill(e->second.m_cache_index,time); - else if ( m_config.m_alloc_policy == ON_FILL ) - m_tag_array->fill(e->second.m_block_addr,time); - else abort(); - bool has_atomic = false; - m_mshrs.mark_ready(e->second.m_block_addr, has_atomic); - if (has_atomic) { - assert(m_config.m_alloc_policy == ON_MISS); - cache_block_t &block = m_tag_array->get_block(e->second.m_cache_index); - block.m_status = MODIFIED; // mark line as dirty for atomic operation - } - m_extra_mf_fields.erase(mf); + extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf); + assert( e != m_extra_mf_fields.end() ); + assert( e->second.m_valid ); + mf->set_data_size( e->second.m_data_size ); + if ( m_config.m_alloc_policy == ON_MISS ) + m_tag_array->fill(e->second.m_cache_index,time); + else if ( m_config.m_alloc_policy == ON_FILL ) + m_tag_array->fill(e->second.m_block_addr,time); + else abort(); + bool has_atomic = false; + m_mshrs.mark_ready(e->second.m_block_addr, has_atomic); + if (has_atomic) { + assert(m_config.m_alloc_policy == ON_MISS); + cache_block_t &block = m_tag_array->get_block(e->second.m_cache_index); + block.m_status = MODIFIED; // mark line as dirty for atomic operation + } + m_extra_mf_fields.erase(mf); + m_bandwidth_management.use_fill_port(mf); } /// Checks if mf is waiting to be filled by lower memory level @@ -880,6 +1004,8 @@ data_cache::process_tag_probe( bool wr, mf, time, events, probe_status ); } } + + m_bandwidth_management.use_data_port(mf, access_status, events); return access_status; } diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index 594125e..9a0ea4b 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -133,6 +133,7 @@ public: m_config_string = NULL; // set by option parser m_config_stringPrefL1 = NULL; m_config_stringPrefShared = NULL; + m_data_port_width = 0; } void init(char * config, FuncCache status) { @@ -140,10 +141,11 @@ public: assert( config ); char rp, wp, ap, mshr_type, wap; - int ntok = sscanf(config,"%u:%u:%u,%c:%c:%c:%c,%c:%u:%u,%u:%u", + int ntok = sscanf(config,"%u:%u:%u,%c:%c:%c:%c,%c:%u:%u,%u:%u,%u", &m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap, &wap, &mshr_type, &m_mshr_entries,&m_mshr_max_merge, - &m_miss_queue_size,&m_result_fifo_entries); + &m_miss_queue_size,&m_result_fifo_entries, + &m_data_port_width); if ( ntok < 11 ) { if ( !strcmp(config,"none") ) { @@ -198,6 +200,12 @@ public: // are stalling each other. assert(0 && "Invalid cache configuration: Writeback cache cannot allocate new line on fill. "); } + + // default: port to data array width and granularity = line size + if (m_data_port_width == 0) { + m_data_port_width = m_line_sz; + } + assert(m_line_sz % m_data_port_width == 0); } bool disabled() const { return m_disabled;} unsigned get_line_sz() const @@ -278,6 +286,8 @@ protected: }; unsigned m_result_fifo_entries; + unsigned m_data_port_width; //< number of byte the cache can access per cycle + friend class tag_array; friend class baseline_cache; friend class read_only_cache; @@ -415,6 +425,10 @@ struct cache_sub_stats{ unsigned pending_hits; unsigned res_fails; + unsigned long long port_available_cycles; + unsigned long long data_port_busy_cycles; + unsigned long long fill_port_busy_cycles; + cache_sub_stats(){ clear(); } @@ -423,6 +437,9 @@ struct cache_sub_stats{ misses = 0; pending_hits = 0; res_fails = 0; + port_available_cycles = 0; + data_port_busy_cycles = 0; + fill_port_busy_cycles = 0; } cache_sub_stats &operator+=(const cache_sub_stats &css){ /// @@ -432,6 +449,9 @@ struct cache_sub_stats{ misses += css.misses; pending_hits += css.pending_hits; res_fails += css.res_fails; + port_available_cycles += css.port_available_cycles; + data_port_busy_cycles += css.data_port_busy_cycles; + fill_port_busy_cycles += css.fill_port_busy_cycles; return *this; } @@ -444,8 +464,13 @@ struct cache_sub_stats{ ret.misses = misses + cs.misses; ret.pending_hits = pending_hits + cs.pending_hits; ret.res_fails = res_fails + cs.res_fails; + ret.port_available_cycles = port_available_cycles + cs.port_available_cycles; + ret.data_port_busy_cycles = data_port_busy_cycles + cs.data_port_busy_cycles; + ret.fill_port_busy_cycles = fill_port_busy_cycles + cs.fill_port_busy_cycles; return ret; } + + void print_port_stats(FILE *fout, const char *cache_name) const; }; /// @@ -469,16 +494,25 @@ public: unsigned get_stats(enum mem_access_type *access_type, unsigned num_access_type, enum cache_request_status *access_status, unsigned num_access_status) const; void get_sub_stats(struct cache_sub_stats &css) const; + void sample_cache_port_utility(bool data_port_busy, bool fill_port_busy); private: bool check_valid(int type, int status) const; std::vector< std::vector<unsigned> > m_stats; + + unsigned long long m_cache_port_available_cycles; + unsigned long long m_cache_data_port_busy_cycles; + unsigned long long m_cache_fill_port_busy_cycles; }; class cache_t { public: virtual ~cache_t() {} virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ) = 0; + + // accessors for cache bandwidth availability + virtual bool data_port_free() const = 0; + virtual bool fill_port_free() const = 0; }; bool was_write_sent( const std::list<cache_event> &events ); @@ -491,7 +525,9 @@ class baseline_cache : public cache_t { public: baseline_cache( const char *name, cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, enum mem_fetch_status status ) - : m_config(config), m_tag_array(new tag_array(config,core_id,type_id)), m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge) + : m_config(config), m_tag_array(new tag_array(config,core_id,type_id)), + m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge), + m_bandwidth_management(config) { init( name, config, memport, status ); } @@ -546,6 +582,10 @@ public: m_stats.get_sub_stats(css); } + // accessors for cache bandwidth availability + bool data_port_free() const { return m_bandwidth_management.data_port_free(); } + bool fill_port_free() const { return m_bandwidth_management.fill_port_free(); } + protected: // Constructor that can be used by derived classes with custom tag arrays baseline_cache( const char *name, @@ -557,7 +597,8 @@ protected: tag_array* new_tag_array ) : m_config(config), m_tag_array( new_tag_array ), - m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge) + m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge), + m_bandwidth_management(config) { init( name, config, memport, status ); } @@ -602,6 +643,34 @@ protected: /// Read miss handler. Check MSHR hit or MSHR available void send_read_request(new_addr_type addr, new_addr_type block_addr, unsigned cache_index, mem_fetch *mf, unsigned time, bool &do_miss, bool &wb, cache_block_t &evicted, std::list<cache_event> &events, bool read_only, bool wa); + + /// Sub-class containing all metadata for port bandwidth management + class bandwidth_management + { + public: + bandwidth_management(cache_config &config); + + /// use the data port based on the outcome and events generated by the mem_fetch request + void use_data_port(mem_fetch *mf, enum cache_request_status outcome, const std::list<cache_event> &events); + + /// use the fill port + void use_fill_port(mem_fetch *mf); + + /// called every cache cycle to free up the ports + void replenish_port_bandwidth(); + + /// query for data port availability + bool data_port_free() const; + /// query for fill port availability + bool fill_port_free() const; + protected: + const cache_config &m_config; + + int m_data_port_occupied_cycles; //< Number of cycle that the data port remains used + int m_fill_port_occupied_cycles; //< Number of cycle that the fill port remains used + }; + + bandwidth_management m_bandwidth_management; }; /// Read only cache @@ -909,6 +978,10 @@ public: mem_fetch *next_access(){return m_result_fifo.pop();} void display_state( FILE *fp ) const; + // accessors for cache bandwidth availability - stubs for now + bool data_port_free() const { return true; } + bool fill_port_free() const { return true; } + // Stat collection const cache_stats &get_stats() const { return m_stats; diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index 475833f..53d13fa 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -957,6 +957,7 @@ void gpgpu_sim::gpu_print_stat() printf("L2_total_cache_reservation_fails = %u\n", total_l2_css.res_fails); printf("L2_total_cache_breakdown:\n"); l2_stats.print_stats(stdout, "L2_cache_stats_breakdown"); + total_l2_css.print_port_stats(stdout, "L2_cache"); } } diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index c589e6c..2bfc7e9 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -353,9 +353,11 @@ void memory_sub_partition::cache_cycle( unsigned cycle ) if ( !m_dram_L2_queue->empty() ) { mem_fetch *mf = m_dram_L2_queue->top(); if ( !m_config->m_L2_config.disabled() && m_L2cache->waiting_for_fill(mf) ) { - mf->set_status(IN_PARTITION_L2_FILL_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); - m_L2cache->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); - m_dram_L2_queue->pop(); + if (m_L2cache->fill_port_free()) { + mf->set_status(IN_PARTITION_L2_FILL_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2cache->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_dram_L2_queue->pop(); + } } else if ( !m_L2_icnt_queue->full() ) { mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); m_L2_icnt_queue->push(mf); @@ -374,7 +376,9 @@ void memory_sub_partition::cache_cycle( unsigned cycle ) ( (m_config->m_L2_texure_only && mf->istexture()) || (!m_config->m_L2_texure_only) ) ) { // L2 is enabled and access is for L2 - if ( !m_L2_icnt_queue->full() ) { + bool output_full = m_L2_icnt_queue->full(); + bool port_free = m_L2cache->data_port_free(); + if ( !output_full && port_free ) { std::list<cache_event> events; enum cache_request_status status = m_L2cache->access(mf->get_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle,events); bool write_sent = was_write_sent(events); @@ -525,7 +529,9 @@ void gpgpu_sim::print_dram_stats(FILE *fout) const unsigned memory_sub_partition::flushL2() { - m_L2cache->flush(); + if (!m_config->m_L2_config.disabled()) { + m_L2cache->flush(); + } return 0; // L2 is read only in this version } @@ -583,11 +589,15 @@ void memory_sub_partition::set_done( mem_fetch *mf ) } void memory_sub_partition::accumulate_L2cache_stats(class cache_stats &l2_stats) const { - l2_stats += m_L2cache->get_stats(); + if (!m_config->m_L2_config.disabled()) { + l2_stats += m_L2cache->get_stats(); + } } void memory_sub_partition::get_L2cache_sub_stats(struct cache_sub_stats &css) const{ - m_L2cache->get_sub_stats(css); + if (!m_config->m_L2_config.disabled()) { + m_L2cache->get_sub_stats(css); + } } void memory_sub_partition::visualizer_print( gzFile visualizer_file ) diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 73a8a62..eb3748f 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -400,8 +400,10 @@ void shader_core_stats::print( FILE* fout ) const fprintf(fout, "gpgpu_stall_shd_mem[c_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][BK_CONF]); fprintf(fout, "gpgpu_stall_shd_mem[c_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][MSHR_RC_FAIL]); fprintf(fout, "gpgpu_stall_shd_mem[c_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[c_mem][data_port_stall] = %d\n", gpu_stall_shd_mem_breakdown[C_MEM][DATA_PORT_STALL]); fprintf(fout, "gpgpu_stall_shd_mem[t_mem][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][MSHR_RC_FAIL]); fprintf(fout, "gpgpu_stall_shd_mem[t_mem][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][ICNT_RC_FAIL]); + fprintf(fout, "gpgpu_stall_shd_mem[t_mem][data_port_stall] = %d\n", gpu_stall_shd_mem_breakdown[T_MEM][DATA_PORT_STALL]); fprintf(fout, "gpgpu_stall_shd_mem[s_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[S_MEM][BK_CONF]); fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][bk_conf] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][BK_CONF] + @@ -415,6 +417,12 @@ void shader_core_stats::print( FILE* fout ) const gpu_stall_shd_mem_breakdown[L_MEM_LD][COAL_STALL] + gpu_stall_shd_mem_breakdown[L_MEM_ST][COAL_STALL] ); // coalescing stall + bank conflict at data cache + fprintf(fout, "gpgpu_stall_shd_mem[gl_mem][data_port_stall] = %d\n", + gpu_stall_shd_mem_breakdown[G_MEM_LD][DATA_PORT_STALL] + + gpu_stall_shd_mem_breakdown[G_MEM_ST][DATA_PORT_STALL] + + gpu_stall_shd_mem_breakdown[L_MEM_LD][DATA_PORT_STALL] + + gpu_stall_shd_mem_breakdown[L_MEM_ST][DATA_PORT_STALL] + ); // data port stall at data cache fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][mshr_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][MSHR_RC_FAIL]); fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][ICNT_RC_FAIL]); fprintf(fout, "gpgpu_stall_shd_mem[g_mem_ld][wb_icnt_rc] = %d\n", gpu_stall_shd_mem_breakdown[G_MEM_LD][WB_ICNT_RC_FAIL]); @@ -1319,6 +1327,9 @@ mem_stage_stall_type ldst_unit::process_memory_access_queue( cache_t *cache, war if( inst.accessq_empty() ) return result; + if( !cache->data_port_free() ) + return DATA_PORT_STALL; + //const mem_access_t &access = inst.accessq_back(); mem_fetch *mf = m_mf_allocator->alloc(inst,inst.accessq_back()); std::list<cache_event> events; @@ -1771,12 +1782,16 @@ void ldst_unit::cycle() if( !m_response_fifo.empty() ) { mem_fetch *mf = m_response_fifo.front(); if (mf->istexture()) { - m_L1T->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); - m_response_fifo.pop_front(); + if (m_L1T->fill_port_free()) { + m_L1T->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + } } else if (mf->isconst()) { - mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); - m_L1C->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); - m_response_fifo.pop_front(); + if (m_L1C->fill_port_free()) { + mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L1C->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + } } else { if( mf->get_type() == WRITE_ACK || ( m_config->gpgpu_perfect_mem && mf->get_is_write() )) { m_core->store_ack(mf); @@ -1799,8 +1814,10 @@ void ldst_unit::cycle() m_next_global = mf; } } else { - m_L1D->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); - m_response_fifo.pop_front(); + if (m_L1D->fill_port_free()) { + m_L1D->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_response_fifo.pop_front(); + } } } } @@ -2007,6 +2024,7 @@ void gpgpu_sim::shader_print_cache_stats( FILE *fout ) const{ } fprintf(fout, "\tL1D_total_cache_pending_hits = %u\n", total_css.pending_hits); fprintf(fout, "\tL1D_total_cache_reservation_fails = %u\n", total_css.res_fails); + total_css.print_port_stats(fout, "\tL1D_cache"); } // L1C diff --git a/src/gpgpu-sim/stats.h b/src/gpgpu-sim/stats.h index c1b3f2a..6a50f05 100644 --- a/src/gpgpu-sim/stats.h +++ b/src/gpgpu-sim/stats.h @@ -50,6 +50,7 @@ enum mem_stage_stall_type { ICNT_RC_FAIL, COAL_STALL, TLB_STALL, + DATA_PORT_STALL, WB_ICNT_RC_FAIL, WB_CACHE_RSRV_FAIL, N_MEM_STAGE_STALL_TYPE |
