diff options
| author | Wilson Fung <[email protected]> | 2013-07-25 14:06:34 -0800 |
|---|---|---|
| committer | Andrew Boktor <[email protected]> | 2014-08-14 13:50:58 -0700 |
| commit | 84f63f6996db657fe1291b4cc6e08b66422918c4 (patch) | |
| tree | a11db8fb7ca10363ef512496130fd5e95a7f32af /src/gpgpu-sim/gpu-cache.cc | |
| parent | b5e2e7003f5d628d1c9baef08e6f6ae8b43e2ee5 (diff) | |
Adding bandwidth modeling to the cache model.
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 16671]
Diffstat (limited to 'src/gpgpu-sim/gpu-cache.cc')
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 160 |
1 files changed, 143 insertions, 17 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; } |
