summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpgpu-sim/gpu-cache.cc160
-rw-r--r--src/gpgpu-sim/gpu-cache.h81
-rw-r--r--src/gpgpu-sim/gpu-sim.cc1
-rw-r--r--src/gpgpu-sim/l2cache.cc24
-rw-r--r--src/gpgpu-sim/shader.cc32
-rw-r--r--src/gpgpu-sim/stats.h1
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