summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim
diff options
context:
space:
mode:
authorMahmoud <[email protected]>2017-10-11 20:05:51 -0400
committerMahmoud <[email protected]>2017-10-11 20:58:12 -0400
commit928351f92300b3517c96f5fabff02b245c87044a (patch)
tree12b4e8e120ee24fe7cb0f55c159d7e38efabd34c /src/gpgpu-sim
parent57b0578fcf9f38fdf6ef2828f2ff71e30c7d7098 (diff)
parente643e2e56344db6264b17d7ffce28f22c8fbabe8 (diff)
Merge branch 'dev-purdue-integration' of https://github.rcac.purdue.edu/abdallm/gpgpu-sim_distribution into dev-purdue-integration
Diffstat (limited to 'src/gpgpu-sim')
-rw-r--r--src/gpgpu-sim/delayqueue.h1
-rw-r--r--src/gpgpu-sim/gpu-cache.cc568
-rw-r--r--src/gpgpu-sim/gpu-cache.h487
-rw-r--r--src/gpgpu-sim/gpu-sim.cc13
-rw-r--r--src/gpgpu-sim/l2cache.cc115
-rw-r--r--src/gpgpu-sim/l2cache.h3
-rw-r--r--src/gpgpu-sim/mem_fetch.cc4
-rw-r--r--src/gpgpu-sim/mem_fetch.h4
8 files changed, 993 insertions, 202 deletions
diff --git a/src/gpgpu-sim/delayqueue.h b/src/gpgpu-sim/delayqueue.h
index b25f143..0caa5d4 100644
--- a/src/gpgpu-sim/delayqueue.h
+++ b/src/gpgpu-sim/delayqueue.h
@@ -161,6 +161,7 @@ public:
}
bool full() const { return (m_max_len && m_length >= m_max_len); }
+ bool is_avilable_size(unsigned size) const { return (m_max_len && m_length+size-1 >= m_max_len); }
bool empty() const { return m_head == NULL; }
unsigned get_n_element() const { return m_n_element; }
unsigned get_length() const { return m_length; }
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index 7af7db0..9633874 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -38,7 +38,8 @@ const char * cache_request_status_str(enum cache_request_status status)
"HIT",
"HIT_RESERVED",
"MISS",
- "RESERVATION_FAIL"
+ "RESERVATION_FAIL",
+ "SECTOR_MISS"
};
assert(sizeof(static_cache_request_status_str) / sizeof(const char*) == NUM_CACHE_REQUEST_STATUS);
@@ -47,6 +48,22 @@ const char * cache_request_status_str(enum cache_request_status status)
return static_cache_request_status_str[status];
}
+const char * cache_fail_status_str(enum cache_reservation_fail_reason status)
+{
+ static const char * static_cache_reservation_fail_reason_str[] = {
+ "LINE_ALLOC_FAIL",
+ "MISS_QUEUE_FULL",
+ "MSHR_ENRTY_FAIL",
+ "MSHR_MERGE_ENRTY_FAIL",
+ "MSHR_RW_PENDING"
+ };
+
+ assert(sizeof(static_cache_reservation_fail_reason_str) / sizeof(const char*) == NUM_CACHE_RESERVATION_FAIL_STATUS);
+ assert(status < NUM_CACHE_RESERVATION_FAIL_STATUS);
+
+ return static_cache_reservation_fail_reason_str[status];
+}
+
unsigned l1d_cache_config::set_index(new_addr_type addr) const{
unsigned set_index = m_nset; // Default to linear set index function
unsigned lower_xor = 0;
@@ -113,13 +130,16 @@ unsigned l2_cache_config::set_index(new_addr_type addr) const{
tag_array::~tag_array()
{
+ unsigned cache_lines_num = MAX_DEFAULT_CACHE_SIZE_MULTIBLIER*m_config.get_num_lines();
+ for(unsigned i=0; i<cache_lines_num; ++i)
+ delete m_lines[i];
delete[] m_lines;
}
tag_array::tag_array( cache_config &config,
int core_id,
int type_id,
- cache_block_t* new_lines)
+ cache_block_t** new_lines)
: m_config( config ),
m_lines( new_lines )
{
@@ -137,7 +157,21 @@ tag_array::tag_array( cache_config &config,
: m_config( config )
{
//assert( m_config.m_write_policy == READ_ONLY ); Old assert
- m_lines = new cache_block_t[MAX_DEFAULT_CACHE_SIZE_MULTIBLIER*config.get_num_lines()];
+ unsigned cache_lines_num = MAX_DEFAULT_CACHE_SIZE_MULTIBLIER*config.get_num_lines();
+ m_lines = new cache_block_t*[cache_lines_num];
+ if(config.m_cache_type == NORMAL)
+ {
+ for(unsigned i=0; i<cache_lines_num; ++i)
+ m_lines[i] = new line_cache_block();
+ }
+ else if(config.m_cache_type == SECTOR)
+ {
+ for(unsigned i=0; i<cache_lines_num; ++i)
+ m_lines[i] = new sector_cache_block();
+ }
+ else
+ assert(0);
+
init( core_id, type_id );
}
@@ -147,6 +181,7 @@ void tag_array::init( int core_id, int type_id )
m_miss = 0;
m_pending_hit = 0;
m_res_fail = 0;
+ m_sector_miss = 0;
// initialize snapshot counters for visualizer
m_prev_snapshot_access = 0;
m_prev_snapshot_miss = 0;
@@ -155,10 +190,11 @@ void tag_array::init( int core_id, int type_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, mem_fetch* mf) 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);
+ mem_access_sector_mask_t mask = mf->get_access_sector_mask();
unsigned invalid_line = (unsigned)-1;
unsigned valid_line = (unsigned)-1;
@@ -169,35 +205,38 @@ enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx )
// 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];
+ cache_block_t *line = m_lines[index];
if (line->m_tag == tag) {
- if ( line->m_status == RESERVED ) {
+ if ( line->get_status(mask) == RESERVED ) {
idx = index;
return HIT_RESERVED;
- } else if ( line->m_status == VALID ) {
+ } else if ( line->get_status(mask) == VALID ) {
idx = index;
return HIT;
- } else if ( line->m_status == MODIFIED ) {
+ } else if ( line->get_status(mask) == MODIFIED ) {
idx = index;
return HIT;
- } else {
- assert( line->m_status == INVALID );
+ } else if ( line->is_valid_line() && line->get_status(mask) == INVALID ) {
+ idx = index;
+ return SECTOR_MISS;
+ }else {
+ assert( line->get_status(mask) == INVALID );
}
}
- if (line->m_status != RESERVED) {
+ if (!line->is_reserved_line()) {
all_reserved = false;
- if (line->m_status == INVALID) {
+ if (line->is_invalid_line()) {
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;
+ if ( line->get_last_access_time() < valid_timestamp ) {
+ valid_timestamp = line->get_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;
+ if ( line->get_alloc_time() < valid_timestamp ) {
+ valid_timestamp = line->get_alloc_time();
valid_line = index;
}
}
@@ -218,37 +257,45 @@ enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx )
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, mem_fetch* mf)
{
bool wb=false;
- cache_block_t evicted;
- enum cache_request_status result = access(addr,time,idx,wb,evicted);
+ evicted_block_info evicted;
+ enum cache_request_status result = access(addr,time,idx,wb,evicted,mf);
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 )
+enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, unsigned &idx, bool &wb, evicted_block_info &evicted, mem_fetch* mf )
{
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);
+ enum cache_request_status status = probe(addr,idx,mf);
switch (status) {
case HIT_RESERVED:
m_pending_hit++;
case HIT:
- m_lines[idx].m_last_access_time=time;
+ m_lines[idx]->set_last_access_time(time, mf->get_access_sector_mask());
break;
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_lines[idx].m_status == MODIFIED ) {
+ if( m_lines[idx]->is_modified_line()) {
wb = true;
- evicted = m_lines[idx];
+ evicted.set_info(m_lines[idx]->m_block_addr, m_lines[idx]->get_modified_size());
}
- m_lines[idx].allocate( m_config.tag(addr), m_config.block_addr(addr), time );
+ m_lines[idx]->allocate( m_config.tag(addr), m_config.block_addr(addr), time, mf->get_access_sector_mask());
}
break;
+ case SECTOR_MISS:
+ assert(m_config.m_cache_type == SECTOR);
+ m_sector_miss++;
+ shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
+ if ( m_config.m_alloc_policy == ON_MISS ) {
+ ((sector_cache_block*)m_lines[idx])->allocate_sector( time, mf->get_access_sector_mask() );
+ }
+ break;
case RESERVATION_FAIL:
m_res_fail++;
shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
@@ -261,37 +308,44 @@ enum cache_request_status tag_array::access( new_addr_type addr, unsigned time,
return status;
}
-void tag_array::fill( new_addr_type addr, unsigned time )
+void tag_array::fill( new_addr_type addr, unsigned time, mem_fetch* mf)
{
assert( m_config.m_alloc_policy == ON_FILL );
unsigned idx;
- enum cache_request_status status = probe(addr,idx);
- assert(status==MISS); // MSHR should have prevented redundant memory request
- m_lines[idx].allocate( m_config.tag(addr), m_config.block_addr(addr), time );
- m_lines[idx].fill(time);
+ enum cache_request_status status = probe(addr,idx,mf);
+ assert(status==MISS||status==SECTOR_MISS); // MSHR should have prevented redundant memory request
+ if(status==MISS)
+ m_lines[idx]->allocate( m_config.tag(addr), m_config.block_addr(addr), time, mf->get_access_sector_mask() );
+ else if (status==SECTOR_MISS) {
+ assert(m_config.m_cache_type == SECTOR);
+ ((sector_cache_block*)m_lines[idx])->allocate_sector( time, mf->get_access_sector_mask() );
+ }
+
+ m_lines[idx]->fill(time, mf->get_access_sector_mask());
}
-void tag_array::fill( unsigned index, unsigned time )
+void tag_array::fill( unsigned index, unsigned time, mem_fetch* mf)
{
assert( m_config.m_alloc_policy == ON_MISS );
- m_lines[index].fill(time);
+ m_lines[index]->fill(time, mf->get_access_sector_mask());
}
void tag_array::flush()
{
for (unsigned i=0; i < m_config.get_num_lines(); i++)
- m_lines[i].m_status = INVALID;
+ for(unsigned j=0; j < SECTOR_CHUNCK_SIZE; j++)
+ m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j)) ;
}
float tag_array::windowed_miss_rate( ) const
{
unsigned n_access = m_access - m_prev_snapshot_access;
- unsigned n_miss = m_miss - m_prev_snapshot_miss;
+ unsigned n_miss = (m_miss+m_sector_miss) - m_prev_snapshot_miss;
// unsigned n_pending_hit = m_pending_hit - m_prev_snapshot_pending_hit;
float missrate = 0.0f;
if (n_access != 0)
- missrate = (float) n_miss / n_access;
+ missrate = (float) (n_miss+m_sector_miss) / n_access;
return missrate;
}
@@ -299,23 +353,24 @@ void tag_array::new_window()
{
m_prev_snapshot_access = m_access;
m_prev_snapshot_miss = m_miss;
+ m_prev_snapshot_miss = m_miss + m_sector_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), PendingHit = %d (%.3g)\n",
- m_access, m_miss, (float) m_miss / m_access,
+ fprintf( stream, "\t\tAccess = %d, Miss = %d, Sector_Miss = %d, Total_Miss = %d (%.3g), PendingHit = %d (%.3g)\n",
+ m_access, m_miss, m_sector_miss, (m_miss+m_sector_miss), (float) (m_miss+m_sector_miss) / m_access,
m_pending_hit, (float) m_pending_hit / m_access);
- total_misses+=m_miss;
+ total_misses+=(m_miss+m_sector_miss);
total_access+=m_access;
}
void tag_array::get_stats(unsigned &total_access, unsigned &total_misses, unsigned &total_hit_res, unsigned &total_res_fail) const{
// Update statistics from the tag array
total_access = m_access;
- total_misses = m_miss;
+ total_misses = (m_miss+m_sector_miss);
total_hit_res = m_pending_hit;
total_res_fail = m_res_fail;
}
@@ -324,16 +379,17 @@ void tag_array::get_stats(unsigned &total_access, unsigned &total_misses, unsign
bool was_write_sent( const std::list<cache_event> &events )
{
for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( *e == WRITE_REQUEST_SENT )
+ if( (*e).m_cache_event_type == WRITE_REQUEST_SENT )
return true;
}
return false;
}
-bool was_writeback_sent( const std::list<cache_event> &events )
+bool was_writeback_sent( const std::list<cache_event> &events, cache_event& wb_event)
{
for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( *e == WRITE_BACK_REQUEST_SENT )
+ if( (*e).m_cache_event_type == WRITE_BACK_REQUEST_SENT )
+ wb_event = *e;
return true;
}
return false;
@@ -342,7 +398,16 @@ bool was_writeback_sent( const std::list<cache_event> &events )
bool was_read_sent( const std::list<cache_event> &events )
{
for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
- if( *e == READ_REQUEST_SENT )
+ if( (*e).m_cache_event_type == READ_REQUEST_SENT )
+ return true;
+ }
+ return false;
+}
+
+bool was_writeallocate_sent( const std::list<cache_event> &events )
+{
+ for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) {
+ if( (*e).m_cache_event_type == WRITE_ALLOCATE_SENT )
return true;
}
return false;
@@ -375,11 +440,27 @@ void mshr_table::add( new_addr_type block_addr, mem_fetch *mf ){
}
}
+/// check is_read_after_write_pending
+bool mshr_table::is_read_after_write_pending( new_addr_type block_addr){
+ std::list<mem_fetch*> my_list = m_data[block_addr].m_list;
+ bool write_found = false;
+ for (std::list<mem_fetch*>::iterator it=my_list.begin(); it != my_list.end(); ++it)
+ {
+ if((*it)->is_write()) //Pending Write Request
+ write_found = true;
+ else if(write_found) //Pending Read Request and we found previous Write
+ return true;
+ }
+
+ return false;
+
+}
+
/// Accept a new cache fill response: mark entry ready for processing
void mshr_table::mark_ready( new_addr_type block_addr, bool &has_atomic ){
assert( !busy() );
table::iterator a = m_data.find(block_addr);
- assert( a != m_data.end() ); // don't remove same request twice
+ assert( a != m_data.end() );
m_current_response.push_back( block_addr );
has_atomic = a->second.m_has_atomic;
assert( m_current_response.size() <= m_data.size() );
@@ -417,9 +498,11 @@ void mshr_table::display( FILE *fp ) const{
/***************************************************************** Caches *****************************************************************/
cache_stats::cache_stats(){
m_stats.resize(NUM_MEM_ACCESS_TYPE);
+ m_fail_stats.resize(NUM_MEM_ACCESS_TYPE);
for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){
m_stats[i].resize(NUM_CACHE_REQUEST_STATUS, 0);
- }
+ m_fail_stats[i].resize(NUM_CACHE_RESERVATION_FAIL_STATUS, 0);
+ }
m_cache_port_available_cycles = 0;
m_cache_data_port_busy_cycles = 0;
m_cache_fill_port_busy_cycles = 0;
@@ -431,7 +514,8 @@ 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);
- }
+ std::fill(m_fail_stats[i].begin(), m_fail_stats[i].end(), 0);
+ }
m_cache_port_available_cycles = 0;
m_cache_data_port_busy_cycles = 0;
m_cache_fill_port_busy_cycles = 0;
@@ -446,6 +530,14 @@ void cache_stats::inc_stats(int access_type, int access_outcome){
m_stats[access_type][access_outcome]++;
}
+void cache_stats::inc_fail_stats(int access_type, int fail_outcome){
+
+ if(!check_fail_valid(access_type, fail_outcome))
+ assert(0 && "Unknown cache access type or access fail");
+
+ m_fail_stats[access_type][fail_outcome]++;
+}
+
enum cache_request_status cache_stats::select_stats_status(enum cache_request_status probe, enum cache_request_status access) const {
///
@@ -454,29 +546,47 @@ enum cache_request_status cache_stats::select_stats_status(enum cache_request_st
///
if(probe == HIT_RESERVED && access != RESERVATION_FAIL)
return probe;
+ else if(probe == SECTOR_MISS && access == MISS)
+ return probe;
else
return access;
}
-unsigned &cache_stats::operator()(int access_type, int access_outcome){
+unsigned &cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome){
///
/// Simple method to read/modify the stat corresponding to (access_type, access_outcome)
/// Used overloaded () to avoid the need for separate read/write member functions
///
- if(!check_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or access outcome");
+ if(fail_outcome) {
+ if(!check_fail_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or fail outcome");
- return m_stats[access_type][access_outcome];
+ return m_fail_stats[access_type][access_outcome];
+ }
+ else {
+ if(!check_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or access outcome");
+
+ return m_stats[access_type][access_outcome];
+ }
}
-unsigned cache_stats::operator()(int access_type, int access_outcome) const{
+unsigned cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome) const{
///
/// Const accessor into m_stats.
///
- if(!check_valid(access_type, access_outcome))
- assert(0 && "Unknown cache access type or access outcome");
+ if(fail_outcome) {
+ if(!check_fail_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or fail outcome");
+
+ return m_fail_stats[access_type][access_outcome];
+ }
+ else {
+ if(!check_valid(access_type, access_outcome))
+ assert(0 && "Unknown cache access type or access outcome");
- return m_stats[access_type][access_outcome];
+ return m_stats[access_type][access_outcome];
+ }
}
cache_stats cache_stats::operator+(const cache_stats &cs){
@@ -486,9 +596,12 @@ cache_stats cache_stats::operator+(const cache_stats &cs){
cache_stats ret;
for(unsigned type=0; type<NUM_MEM_ACCESS_TYPE; ++type){
for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){
- ret(type, status) = m_stats[type][status] + cs(type, status);
+ ret(type, status, false) = m_stats[type][status] + cs(type, status, false);
+ }
+ for(unsigned status=0; status<NUM_CACHE_RESERVATION_FAIL_STATUS; ++status){
+ ret(type, status, true) = m_fail_stats[type][status] + cs(type, status, true);
+ }
}
- }
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;
@@ -501,8 +614,11 @@ cache_stats &cache_stats::operator+=(const cache_stats &cs){
///
for(unsigned type=0; type<NUM_MEM_ACCESS_TYPE; ++type){
for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){
- m_stats[type][status] += cs(type, status);
+ m_stats[type][status] += cs(type, status, false);
}
+ for(unsigned status=0; status<NUM_CACHE_RESERVATION_FAIL_STATUS; ++status){
+ m_fail_stats[type][status] += cs(type, status, true);
+ }
}
m_cache_port_available_cycles += cs.m_cache_port_available_cycles;
m_cache_data_port_busy_cycles += cs.m_cache_data_port_busy_cycles;
@@ -517,6 +633,8 @@ void cache_stats::print_stats(FILE *fout, const char *cache_name) const{
/// the provided name is used.
/// The printed format is "<cache_name>[<request_type>][<request_status>] = <stat_value>"
///
+ std::vector< unsigned > total_access;
+ total_access.resize(NUM_MEM_ACCESS_TYPE, 0);
std::string m_cache_name = cache_name;
for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
@@ -526,9 +644,34 @@ void cache_stats::print_stats(FILE *fout, const char *cache_name) const{
mem_access_type_str((enum mem_access_type)type),
cache_request_status_str((enum cache_request_status)status),
m_stats[type][status]);
+ if(status != RESERVATION_FAIL)
+ total_access[type]+= m_stats[type][status];
}
}
}
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ if(total_access[type] > 0)
+ fprintf(fout, "\t%s[%s][%s] = %u\n",
+ m_cache_name.c_str(),
+ mem_access_type_str((enum mem_access_type)type),
+ "TOTAL_ACCESS",
+ total_access[type]);
+ }
+}
+
+void cache_stats::print_fail_stats(FILE *fout, const char *cache_name) const{
+ std::string m_cache_name = cache_name;
+ for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
+ for (unsigned fail = 0; fail < NUM_CACHE_RESERVATION_FAIL_STATUS; ++fail) {
+ if(m_fail_stats[type][fail] > 0){
+ fprintf(fout, "\t%s[%s][%s] = %u\n",
+ m_cache_name.c_str(),
+ mem_access_type_str((enum mem_access_type)type),
+ cache_fail_status_str((enum cache_reservation_fail_reason)fail),
+ m_fail_stats[type][fail]);
+ }
+ }
+ }
}
void cache_sub_stats::print_port_stats(FILE *fout, const char *cache_name) const
@@ -570,10 +713,10 @@ void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{
for (unsigned type = 0; type < NUM_MEM_ACCESS_TYPE; ++type) {
for (unsigned status = 0; status < NUM_CACHE_REQUEST_STATUS; ++status) {
- if(status == HIT || status == MISS || status == HIT_RESERVED)
+ if(status == HIT || status == MISS || status == SECTOR_MISS || status == HIT_RESERVED)
t_css.accesses += m_stats[type][status];
- if(status == MISS)
+ if(status == MISS || status == SECTOR_MISS)
t_css.misses += m_stats[type][status];
if(status == HIT_RESERVED)
@@ -601,6 +744,16 @@ bool cache_stats::check_valid(int type, int status) const{
return false;
}
+bool cache_stats::check_fail_valid(int type, int fail) const{
+ ///
+ /// Verify a valid access_type/access_status
+ ///
+ if((type >= 0) && (type < NUM_MEM_ACCESS_TYPE) && (fail >= 0) && (fail < NUM_CACHE_RESERVATION_FAIL_STATUS))
+ return true;
+ else
+ return false;
+}
+
void cache_stats::sample_cache_port_utility(bool data_port_busy, bool fill_port_busy)
{
m_cache_port_available_cycles += 1;
@@ -629,15 +782,18 @@ void baseline_cache::bandwidth_management::use_data_port(mem_fetch *mf, enum cac
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 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;
+ // in case of sector cache we need to write bank only the modified sectors
+ cache_event ev(WRITE_BACK_REQUEST_SENT);
+ if (was_writeback_sent(events, ev)) {
+ unsigned data_cycles = ev.m_evicted_block.m_modified_size / port_width;
m_data_port_occupied_cycles += data_cycles;
}
} break;
- case RESERVATION_FAIL:
+ case SECTOR_MISS:
+ case RESERVATION_FAIL:
// Does not consume any port bandwidth
break;
default:
@@ -650,7 +806,7 @@ void baseline_cache::bandwidth_management::use_data_port(mem_fetch *mf, enum cac
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;
+ unsigned fill_cycles = m_config.get_atom_sz() / m_config.m_data_port_width;
m_fill_port_occupied_cycles += fill_cycles;
}
@@ -697,21 +853,40 @@ void baseline_cache::cycle(){
/// Interface for response from lower memory level (model bandwidth restictions in caller)
void baseline_cache::fill(mem_fetch *mf, unsigned time){
+
+ if(m_config.m_mshr_type == SECTOR_ASSOC) {
+ assert(mf->original_mf);
+ extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf->original_mf);
+ assert( e != m_extra_mf_fields.end() );
+ e->second.pending_read--;
+
+ if(e->second.pending_read > 0) {
+ //wait for the other requests to come back
+ delete mf;
+ return;
+ } else {
+ mem_fetch *temp = mf;
+ mf = mf->original_mf;
+ delete temp;
+ }
+ }
+
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 );
+ mf->set_addr( e->second.m_addr );
if ( m_config.m_alloc_policy == ON_MISS )
- m_tag_array->fill(e->second.m_cache_index,time);
+ m_tag_array->fill(e->second.m_cache_index,time,mf);
else if ( m_config.m_alloc_policy == ON_FILL )
- m_tag_array->fill(e->second.m_block_addr,time);
+ m_tag_array->fill(e->second.m_block_addr,time,mf);
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
+ cache_block_t* block = m_tag_array->get_block(e->second.m_cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask()); // mark line as dirty for atomic operation
}
m_extra_mf_fields.erase(mf);
m_bandwidth_management.use_fill_port(mf);
@@ -739,45 +914,56 @@ void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_a
unsigned time, bool &do_miss, std::list<cache_event> &events, bool read_only, bool wa){
bool wb=false;
- cache_block_t e;
+ evicted_block_info e;
send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, e, events, read_only, wa);
}
/// Read miss handler. Check MSHR hit or MSHR available
void baseline_cache::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){
+ unsigned time, bool &do_miss, bool &wb, evicted_block_info &evicted, std::list<cache_event> &events, bool read_only, bool wa){
- bool mshr_hit = m_mshrs.probe(block_addr);
- bool mshr_avail = !m_mshrs.full(block_addr);
+ new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
+ bool mshr_hit = m_mshrs.probe(mshr_addr);
+ bool mshr_avail = !m_mshrs.full(mshr_addr);
if ( mshr_hit && mshr_avail ) {
if(read_only)
- m_tag_array->access(block_addr,time,cache_index);
+ m_tag_array->access(block_addr,time,cache_index,mf);
else
- m_tag_array->access(block_addr,time,cache_index,wb,evicted);
+ m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
- m_mshrs.add(block_addr,mf);
+ m_mshrs.add(mshr_addr,mf);
do_miss = true;
} else if ( !mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size) ) {
if(read_only)
- m_tag_array->access(block_addr,time,cache_index);
+ m_tag_array->access(block_addr,time,cache_index,mf);
else
- m_tag_array->access(block_addr,time,cache_index,wb,evicted);
+ m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
- 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_mshrs.add(mshr_addr,mf);
+ m_extra_mf_fields[mf] = extra_mf_fields(mshr_addr,mf->get_addr(),cache_index, mf->get_data_size(), m_config);
+ mf->set_data_size( m_config.get_atom_sz() );
+ mf->set_addr( block_addr );
m_miss_queue.push_back(mf);
mf->set_status(m_miss_queue_status,time);
- if(!wa)
- events.push_back(READ_REQUEST_SENT);
+ if(wa)
+ events.push_back(cache_event(WRITE_ALLOCATE_SENT));
+ else
+ events.push_back(cache_event(READ_REQUEST_SENT));
do_miss = true;
}
+ else if(mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
+ else if (!mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
+ else
+ assert(0);
}
/// Sends write request to lower level memory (write or writeback)
void data_cache::send_write_request(mem_fetch *mf, cache_event request, unsigned time, std::list<cache_event> &events){
- events.push_back(request);
+
+ events.push_back(request);
m_miss_queue.push_back(mf);
mf->set_status(m_miss_queue_status,time);
}
@@ -788,40 +974,44 @@ void data_cache::send_write_request(mem_fetch *mf, cache_event request, unsigned
/// Write-back hit: Mark block as modified
cache_request_status data_cache::wr_hit_wb(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
new_addr_type block_addr = m_config.block_addr(addr);
- m_tag_array->access(block_addr,time,cache_index); // update LRU state
- cache_block_t &block = m_tag_array->get_block(cache_index);
- block.m_status = MODIFIED;
+ m_tag_array->access(block_addr,time,cache_index,mf); // update LRU state
+ cache_block_t* block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
return HIT;
}
/// Write-through hit: Directly send request to lower level memory
cache_request_status data_cache::wr_hit_wt(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
- if(miss_queue_full(0))
+ if(miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
return RESERVATION_FAIL; // cannot handle request this cycle
+ }
new_addr_type block_addr = m_config.block_addr(addr);
- m_tag_array->access(block_addr,time,cache_index); // update LRU state
- cache_block_t &block = m_tag_array->get_block(cache_index);
- block.m_status = MODIFIED;
+ m_tag_array->access(block_addr,time,cache_index,mf); // update LRU state
+ cache_block_t* block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
// generate a write-through
- send_write_request(mf, WRITE_REQUEST_SENT, time, events);
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
return HIT;
}
/// Write-evict hit: Send request to lower level memory and invalidate corresponding block
cache_request_status data_cache::wr_hit_we(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status ){
- if(miss_queue_full(0))
+ if(miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
return RESERVATION_FAIL; // cannot handle request this cycle
+ }
// generate a write-through/evict
- cache_block_t &block = m_tag_array->get_block(cache_index);
- send_write_request(mf, WRITE_REQUEST_SENT, time, events);
+ cache_block_t* block = m_tag_array->get_block(cache_index);
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
// Invalidate block
- block.m_status = INVALID;
+ block->set_status(INVALID, mf->get_access_sector_mask());
return HIT;
}
@@ -840,35 +1030,46 @@ enum cache_request_status data_cache::wr_hit_global_we_local_wb(new_addr_type ad
/// Write-allocate miss: Send write request to lower level memory
// and send a read request for the same block
enum cache_request_status
-data_cache::wr_miss_wa( new_addr_type addr,
+data_cache::wr_miss_wa_naive( new_addr_type addr,
unsigned cache_index, mem_fetch *mf,
unsigned time, std::list<cache_event> &events,
enum cache_request_status status )
{
new_addr_type block_addr = m_config.block_addr(addr);
+ new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr());
// Write allocate, maximum 3 requests (write miss, read request, write back request)
// Conservatively ensure the worst-case request can be handled this cycle
- bool mshr_hit = m_mshrs.probe(block_addr);
- bool mshr_avail = !m_mshrs.full(block_addr);
+ bool mshr_hit = m_mshrs.probe(mshr_addr);
+ bool mshr_avail = !m_mshrs.full(mshr_addr);
if(miss_queue_full(2)
|| (!(mshr_hit && mshr_avail)
- && !(!mshr_hit && mshr_avail
- && (m_miss_queue.size() < m_config.m_miss_queue_size))))
+ && !(!mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size)))) {
+ //check what is the exactly the failure reason
+ if(miss_queue_full(2) )
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ else if(mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_MERGE_ENRTY_FAIL);
+ else if (!mshr_hit && !mshr_avail)
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_ENRTY_FAIL);
+ else
+ assert(0);
+
return RESERVATION_FAIL;
+ }
- send_write_request(mf, WRITE_REQUEST_SENT, time, events);
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
// Tries to send write allocate request, returns true on success and false on failure
//if(!send_write_allocate(mf, addr, block_addr, cache_index, time, events))
// return RESERVATION_FAIL;
const mem_access_t *ma = new mem_access_t( m_wr_alloc_type,
mf->get_addr(),
- mf->get_data_size(),
+ m_config.get_atom_sz(),
false, // Now performing a read
mf->get_access_warp_mask(),
mf->get_access_byte_mask(),
- mf->get_access_sector_mask());
+ mf->get_access_sector_mask());
mem_fetch *n_mf = new mem_fetch( *ma,
NULL,
@@ -880,7 +1081,7 @@ data_cache::wr_miss_wa( new_addr_type addr,
bool do_miss = false;
bool wb = false;
- cache_block_t evicted;
+ evicted_block_info evicted;
// Send read request resulting from write miss
send_read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb,
@@ -890,10 +1091,10 @@ data_cache::wr_miss_wa( new_addr_type addr,
// If evicted block is modified and not a write-through
// (already modified lower level)
if( wb && (m_config.m_write_policy != WRITE_THROUGH) ) {
+ assert(status == MISS); //SECTOR_MISS and HIT_RESERVED should not send write back
mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,m_config.get_line_sz(),true);
- m_miss_queue.push_back(wb);
- wb->set_status(m_miss_queue_status,time);
+ m_wrbk_type,evicted.m_modified_size,true);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
}
return MISS;
}
@@ -901,6 +1102,109 @@ data_cache::wr_miss_wa( new_addr_type addr,
return RESERVATION_FAIL;
}
+
+enum cache_request_status
+data_cache::wr_miss_wa_fetch_on_write( new_addr_type addr,
+ unsigned cache_index, mem_fetch *mf,
+ unsigned time, std::list<cache_event> &events,
+ enum cache_request_status status )
+{
+
+ new_addr_type block_addr = m_config.block_addr(addr);
+ new_addr_type mshr_addr = m_config.block_addr(mf->get_addr());
+
+ if(mf->get_access_byte_mask().count() == m_config.get_atom_sz())
+ {
+ //if the request writes to the whole cache line/sector, then, write and set cache line Modified.
+ //and no need to send read request to memory or reserve mshr
+
+ if(miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
+
+ bool wb = false;
+ evicted_block_info evicted;
+
+ cache_request_status status = m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf);
+ assert(status != HIT);
+ cache_block_t* block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask());
+ if(status == HIT_RESERVED)
+ block->set_ignore_on_fill(true, mf->get_access_sector_mask());
+
+ if( status != RESERVATION_FAIL ){
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if( wb && (m_config.m_write_policy != WRITE_THROUGH) ) {
+ mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
+ m_wrbk_type,evicted.m_modified_size,true);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
+ }
+ return MISS;
+ }
+ return RESERVATION_FAIL;
+ }
+ else
+ {
+ if(miss_queue_full(1)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL;
+ }
+
+
+ //prevent Write - Read - Write in pending mshr
+ //allowing another write will override the value of the first write, and the pending read request will read incorrect result from the second write
+ if(m_mshrs.probe(mshr_addr) && m_mshrs.is_read_after_write_pending(mshr_addr) && mf->is_write())
+ {
+ //assert(0);
+ m_stats.inc_fail_stats(mf->get_access_type(), MSHR_RW_PENDING);
+ return RESERVATION_FAIL;
+ }
+
+ const mem_access_t *ma = new mem_access_t( m_wr_alloc_type,
+ mf->get_addr(),
+ m_config.get_atom_sz(),
+ false, // Now performing a read
+ mf->get_access_warp_mask(),
+ mf->get_access_byte_mask(),
+ mf->get_access_sector_mask());
+
+ mem_fetch *n_mf = new mem_fetch( *ma,
+ NULL,
+ mf->get_ctrl_size(),
+ mf->get_wid(),
+ mf->get_sid(),
+ mf->get_tpc(),
+ mf->get_mem_config(),
+ mf);
+
+ new_addr_type block_addr = m_config.block_addr(addr);
+ bool do_miss = false;
+ bool wb = false;
+ evicted_block_info evicted;
+ send_read_request( addr,
+ block_addr,
+ cache_index,
+ n_mf, time, do_miss, wb, evicted, events, false, true);
+
+ cache_block_t* block = m_tag_array->get_block(cache_index);
+ block->set_modified_on_fill(true, mf->get_access_sector_mask());
+
+ if( do_miss ){
+ // If evicted block is modified and not a write-through
+ // (already modified lower level)
+ if(wb && (m_config.m_write_policy != WRITE_THROUGH) ){
+ mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
+ m_wrbk_type,evicted.m_modified_size,true);
+ send_write_request(wb, cache_event(WRITE_BACK_REQUEST_SENT, evicted), time, events);
+ }
+ return MISS;
+ }
+ return RESERVATION_FAIL;
+ }
+}
+
/// No write-allocate miss: Simply send write request to lower level memory
enum cache_request_status
data_cache::wr_miss_no_wa( new_addr_type addr,
@@ -910,11 +1214,14 @@ data_cache::wr_miss_no_wa( new_addr_type addr,
std::list<cache_event> &events,
enum cache_request_status status )
{
- if(miss_queue_full(0))
- return RESERVATION_FAIL; // cannot handle request this cycle
+ if(miss_queue_full(0)) {
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }
+
// on miss, generate write through (no write buffering -- too many threads for that)
- send_write_request(mf, WRITE_REQUEST_SENT, time, events);
+ send_write_request(mf, cache_event(WRITE_REQUEST_SENT), time, events);
return MISS;
}
@@ -932,13 +1239,13 @@ data_cache::rd_hit_base( new_addr_type addr,
enum cache_request_status status )
{
new_addr_type block_addr = m_config.block_addr(addr);
- m_tag_array->access(block_addr,time,cache_index);
+ m_tag_array->access(block_addr,time,cache_index,mf);
// Atomics treated as global read/write requests - Perform read, mark line as
// MODIFIED
if(mf->isatomic()){
assert(mf->get_access_type() == GLOBAL_ACC_R);
- cache_block_t &block = m_tag_array->get_block(cache_index);
- block.m_status = MODIFIED; // mark line as dirty
+ cache_block_t* block = m_tag_array->get_block(cache_index);
+ block->set_status(MODIFIED, mf->get_access_sector_mask()) ; // mark line as dirty
}
return HIT;
}
@@ -954,15 +1261,17 @@ data_cache::rd_miss_base( new_addr_type addr,
unsigned time,
std::list<cache_event> &events,
enum cache_request_status status ){
- if(miss_queue_full(1))
+ if(miss_queue_full(1)) {
// cannot handle request this cycle
// (might need to generate two requests)
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
return RESERVATION_FAIL;
+ }
new_addr_type block_addr = m_config.block_addr(addr);
bool do_miss = false;
bool wb = false;
- cache_block_t evicted;
+ evicted_block_info evicted;
send_read_request( addr,
block_addr,
cache_index,
@@ -973,12 +1282,12 @@ data_cache::rd_miss_base( new_addr_type addr,
// (already modified lower level)
if(wb && (m_config.m_write_policy != WRITE_THROUGH) ){
mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,
- m_wrbk_type,m_config.get_line_sz(),true);
+ m_wrbk_type,evicted.m_modified_size,true);
send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
}
return MISS;
}
- return RESERVATION_FAIL;
+ return RESERVATION_FAIL;
}
/// Access cache for read_only_cache: returns RESERVATION_FAIL if
@@ -989,16 +1298,16 @@ read_only_cache::access( new_addr_type addr,
unsigned time,
std::list<cache_event> &events )
{
- assert( mf->get_data_size() <= m_config.get_line_sz());
+ assert( mf->get_data_size() <= m_config.get_atom_sz());
assert(m_config.m_write_policy == READ_ONLY);
assert(!mf->get_is_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);
+ enum cache_request_status status = m_tag_array->probe(block_addr,cache_index,mf);
enum cache_request_status cache_status = RESERVATION_FAIL;
if ( status == HIT ) {
- cache_status = m_tag_array->access(block_addr,time,cache_index); // update LRU state
+ cache_status = m_tag_array->access(block_addr,time,cache_index,mf); // update LRU state
}else if ( status != RESERVATION_FAIL ) {
if(!miss_queue_full(0)){
bool do_miss=false;
@@ -1009,7 +1318,10 @@ read_only_cache::access( new_addr_type addr,
cache_status = RESERVATION_FAIL;
}else{
cache_status = RESERVATION_FAIL;
+ m_stats.inc_fail_stats(mf->get_access_type(), MISS_QUEUE_FULL);
}
+ }else {
+ m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
}
m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
@@ -1042,6 +1354,9 @@ data_cache::process_tag_probe( bool wr,
access_status = (this->*m_wr_miss)( addr,
cache_index,
mf, time, events, probe_status );
+ }else {
+ //the only reason for reservation fail here is LINE_ALLOC_FAIL (i.e all lines are reserved)
+ m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
}
}else{ // Read
if(probe_status == HIT){
@@ -1052,6 +1367,9 @@ data_cache::process_tag_probe( bool wr,
access_status = (this->*m_rd_miss)( addr,
cache_index,
mf, time, events, probe_status );
+ }else {
+ //the only reason for reservation fail here is LINE_ALLOC_FAIL (i.e all lines are reserved)
+ m_stats.inc_fail_stats(mf->get_access_type(), LINE_ALLOC_FAIL);
}
}
@@ -1071,12 +1389,12 @@ data_cache::access( new_addr_type addr,
std::list<cache_event> &events )
{
- assert( mf->get_data_size() <= m_config.get_line_sz());
+ assert( mf->get_data_size() <= m_config.get_atom_sz());
bool wr = mf->get_is_write();
new_addr_type block_addr = m_config.block_addr(addr);
unsigned cache_index = (unsigned)-1;
enum cache_request_status probe_status
- = m_tag_array->probe( block_addr, cache_index );
+ = m_tag_array->probe( block_addr, cache_index, mf );
enum cache_request_status access_status
= process_tag_probe( wr, probe_status, addr, cache_index, mf, time, events );
m_stats.inc_stats(mf->get_access_type(),
@@ -1125,7 +1443,7 @@ enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf,
// 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;
- enum cache_request_status status = m_tags.access(block_addr,time,cache_index);
+ enum cache_request_status status = m_tags.access(block_addr,time,cache_index,mf);
enum cache_request_status cache_status = RESERVATION_FAIL;
assert( status != RESERVATION_FAIL );
assert( status != HIT_RESERVED ); // as far as tags are concerned: HIT or MISS
@@ -1135,10 +1453,10 @@ enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf,
unsigned rob_index = m_rob.push( rob_entry(cache_index, mf, block_addr) );
m_extra_mf_fields[mf] = extra_mf_fields(rob_index);
mf->set_data_size(m_config.get_line_sz());
- m_tags.fill(cache_index,time); // mark block as valid
+ m_tags.fill(cache_index,time,mf); // mark block as valid
m_request_fifo.push(mf);
mf->set_status(m_request_queue_status,time);
- events.push_back(READ_REQUEST_SENT);
+ events.push_back(cache_event(READ_REQUEST_SENT));
cache_status = MISS;
} else {
// the value *will* *be* in the cache already
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 7535a1d..3e1691a 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -36,6 +36,7 @@
#include "../tr1_hash_map.h"
#include "addrdec.h"
+#include <iostream>
enum cache_block_state {
INVALID,
@@ -49,13 +50,51 @@ enum cache_request_status {
HIT_RESERVED,
MISS,
RESERVATION_FAIL,
+ SECTOR_MISS,
NUM_CACHE_REQUEST_STATUS
};
-enum cache_event {
+enum cache_reservation_fail_reason {
+ LINE_ALLOC_FAIL= 0,// all line are reserved
+ MISS_QUEUE_FULL, // MISS queue (i.e. interconnect or DRAM) is full
+ MSHR_ENRTY_FAIL,
+ MSHR_MERGE_ENRTY_FAIL,
+ MSHR_RW_PENDING,
+ NUM_CACHE_RESERVATION_FAIL_STATUS
+};
+
+enum cache_event_type {
WRITE_BACK_REQUEST_SENT,
READ_REQUEST_SENT,
- WRITE_REQUEST_SENT
+ WRITE_REQUEST_SENT,
+ WRITE_ALLOCATE_SENT
+};
+
+struct evicted_block_info {
+ new_addr_type m_block_addr;
+ unsigned m_modified_size;
+ evicted_block_info() {
+ m_block_addr = 0;
+ m_modified_size = 0;
+ }
+ void set_info(new_addr_type block_addr, unsigned modified_size){
+ m_block_addr = block_addr;
+ m_modified_size = modified_size;
+ }
+};
+
+struct cache_event {
+ enum cache_event_type m_cache_event_type;
+ evicted_block_info m_evicted_block; //if it was write_back event, fill the the evicted block info
+
+ cache_event(enum cache_event_type m_cache_event){
+ m_cache_event_type = m_cache_event;
+ }
+
+ cache_event(enum cache_event_type cache_event, evicted_block_info evicted_block){
+ m_cache_event_type = cache_event;
+ m_evicted_block = evicted_block;
+ }
};
const char * cache_request_status_str(enum cache_request_status status);
@@ -65,33 +104,294 @@ struct cache_block_t {
{
m_tag=0;
m_block_addr=0;
- m_alloc_time=0;
- m_fill_time=0;
- m_last_access_time=0;
- m_status=INVALID;
}
- void allocate( new_addr_type tag, new_addr_type block_addr, unsigned time )
+
+ virtual void allocate( new_addr_type tag, new_addr_type block_addr, unsigned time, mem_access_sector_mask_t sector_mask) = 0;
+ virtual void fill( unsigned time, mem_access_sector_mask_t sector_mask) = 0;
+
+ virtual bool is_invalid_line() = 0;
+ virtual bool is_valid_line() = 0;
+ virtual bool is_reserved_line() = 0;
+ virtual bool is_modified_line() = 0;
+
+ virtual enum cache_block_state get_status( mem_access_sector_mask_t sector_mask) = 0;
+ virtual void set_status(enum cache_block_state m_status, mem_access_sector_mask_t sector_mask) = 0;
+
+ virtual unsigned get_last_access_time() = 0;
+ virtual void set_last_access_time(unsigned time, mem_access_sector_mask_t sector_mask) = 0;
+ virtual unsigned get_alloc_time() = 0;
+ virtual void set_ignore_on_fill(bool m_ignore, mem_access_sector_mask_t sector_mask) = 0;
+ virtual void set_modified_on_fill(bool m_modified, mem_access_sector_mask_t sector_mask) = 0;
+ virtual unsigned get_modified_size() = 0;
+ virtual ~cache_block_t() {}
+
+ new_addr_type m_tag;
+ new_addr_type m_block_addr;
+
+};
+
+struct line_cache_block: public cache_block_t {
+ line_cache_block()
+ {
+ m_alloc_time=0;
+ m_fill_time=0;
+ m_last_access_time=0;
+ m_status=INVALID;
+ m_ignore_on_fill_status = false;
+ m_set_modified_on_fill = false;
+ }
+ void allocate( new_addr_type tag, new_addr_type block_addr, unsigned time, mem_access_sector_mask_t sector_mask )
+ {
+ m_tag=tag;
+ m_block_addr=block_addr;
+ m_alloc_time=time;
+ m_last_access_time=time;
+ m_fill_time=0;
+ m_status=RESERVED;
+ m_ignore_on_fill_status = false;
+ m_set_modified_on_fill = false;
+ }
+ void fill( unsigned time, mem_access_sector_mask_t sector_mask )
+ {
+ if(!m_ignore_on_fill_status)
+ assert( m_status == RESERVED );
+
+ m_status = m_set_modified_on_fill? MODIFIED : VALID;
+
+ m_fill_time=time;
+ }
+ virtual bool is_invalid_line()
+ {
+ return m_status == INVALID;
+ }
+ virtual bool is_valid_line()
+ {
+ return m_status == VALID;
+ }
+ virtual bool is_reserved_line()
+ {
+ return m_status == RESERVED;
+ }
+ virtual bool is_modified_line()
+ {
+ return m_status == MODIFIED;
+ }
+
+ virtual enum cache_block_state get_status(mem_access_sector_mask_t sector_mask)
+ {
+ return m_status;
+ }
+ virtual void set_status(enum cache_block_state status, mem_access_sector_mask_t sector_mask)
+ {
+ m_status = status;
+ }
+ virtual unsigned get_last_access_time()
+ {
+ return m_last_access_time;
+ }
+ virtual void set_last_access_time(unsigned time, mem_access_sector_mask_t sector_mask)
+ {
+ m_last_access_time = time;
+ }
+ virtual unsigned get_alloc_time()
+ {
+ return m_alloc_time;
+ }
+ virtual void set_ignore_on_fill(bool m_ignore, mem_access_sector_mask_t sector_mask)
+ {
+ m_ignore_on_fill_status = m_ignore;
+ }
+ virtual void set_modified_on_fill(bool m_modified, mem_access_sector_mask_t sector_mask)
+ {
+ m_set_modified_on_fill = m_modified;
+ }
+ virtual unsigned get_modified_size()
+ {
+ return SECTOR_CHUNCK_SIZE * SECTOR_SIZE; //i.e. cache line size
+ }
+
+
+private:
+ unsigned m_alloc_time;
+ unsigned m_last_access_time;
+ unsigned m_fill_time;
+ cache_block_state m_status;
+ bool m_ignore_on_fill_status;
+ bool m_set_modified_on_fill;
+};
+
+struct sector_cache_block : public cache_block_t {
+ sector_cache_block()
{
- m_tag=tag;
- m_block_addr=block_addr;
- m_alloc_time=time;
- m_last_access_time=time;
- m_fill_time=0;
- m_status=RESERVED;
+ init();
}
- void fill( unsigned time )
+
+ void init() {
+ for(unsigned i =0; i< SECTOR_CHUNCK_SIZE; ++i) {
+ m_sector_alloc_time[i]= 0;
+ m_sector_fill_time[i]= 0;
+ m_last_sector_access_time[i]= 0;
+ m_status[i]= INVALID;
+ m_ignore_on_fill_status[i] = false;
+ m_set_modified_on_fill[i] = false;
+ }
+ m_line_alloc_time=0;
+ m_line_last_access_time=0;
+ m_line_fill_time=0;
+ }
+
+ virtual void allocate( new_addr_type tag, new_addr_type block_addr, unsigned time, mem_access_sector_mask_t sector_mask )
{
- assert( m_status == RESERVED );
- m_status=VALID;
- m_fill_time=time;
+ allocate_line( tag, block_addr, time, sector_mask );
}
- new_addr_type m_tag;
- new_addr_type m_block_addr;
- unsigned m_alloc_time;
- unsigned m_last_access_time;
- unsigned m_fill_time;
- cache_block_state m_status;
+ void allocate_line( new_addr_type tag, new_addr_type block_addr, unsigned time, mem_access_sector_mask_t sector_mask )
+ {
+ //allocate a new line
+ //assert(m_block_addr != 0 && m_block_addr != block_addr);
+ init();
+ m_tag=tag;
+ m_block_addr=block_addr;
+
+ unsigned sidx = get_sector_index(sector_mask);
+
+ //set sector stats
+ m_sector_alloc_time[sidx]=time;
+ m_last_sector_access_time[sidx]=time;
+ m_sector_fill_time[sidx]=0;
+ m_status[sidx]=RESERVED;
+ m_ignore_on_fill_status[sidx] = false;
+ m_set_modified_on_fill[sidx] = false;
+
+ //set line stats
+ m_line_alloc_time=time; //only set this for the first allocated sector
+ m_line_last_access_time=time;
+ m_line_fill_time=0;
+ }
+
+ void allocate_sector(unsigned time, mem_access_sector_mask_t sector_mask )
+ {
+ //allocate invalid sector of this allocated valid line
+ assert(is_valid_line());
+ unsigned sidx = get_sector_index(sector_mask);
+
+ //set sector stats
+ m_sector_alloc_time[sidx]=time;
+ m_last_sector_access_time[sidx]=time;
+ m_sector_fill_time[sidx]=0;
+ m_status[sidx]=RESERVED;
+ m_ignore_on_fill_status[sidx] = false;
+ m_set_modified_on_fill[sidx] = false;
+
+ //set line stats
+ m_line_last_access_time=time;
+ m_line_fill_time=0;
+ }
+
+ virtual void fill( unsigned time, mem_access_sector_mask_t sector_mask)
+ {
+ unsigned sidx = get_sector_index(sector_mask);
+
+ if(!m_ignore_on_fill_status[sidx])
+ assert( m_status[sidx] == RESERVED );
+
+ m_status[sidx] = m_set_modified_on_fill[sidx]? MODIFIED : VALID;
+
+ m_sector_fill_time[sidx]=time;
+ m_line_fill_time=time;
+ }
+ virtual bool is_invalid_line() {
+ //all the sectors should be invalid
+ for(unsigned i =0; i< SECTOR_CHUNCK_SIZE; ++i) {
+ if (m_status[i] != INVALID)
+ return false;
+ }
+ return true;
+ }
+ virtual bool is_valid_line() { return !(is_invalid_line()); }
+ virtual bool is_reserved_line() {
+ //if any of the sector is reserved, then the line is reserved
+ for(unsigned i =0; i< SECTOR_CHUNCK_SIZE; ++i) {
+ if (m_status[i] == RESERVED)
+ return true;
+ }
+ return false;
+ }
+ virtual bool is_modified_line() {
+ //if any of the sector is modified, then the line is modified
+ for(unsigned i =0; i< SECTOR_CHUNCK_SIZE; ++i) {
+ if (m_status[i] == MODIFIED)
+ return true;
+ }
+ return false;
+ }
+
+ virtual enum cache_block_state get_status(mem_access_sector_mask_t sector_mask)
+ {
+ unsigned sidx = get_sector_index(sector_mask);
+
+ return m_status[sidx];
+ }
+ virtual void set_status(enum cache_block_state status, mem_access_sector_mask_t sector_mask)
+ {
+ unsigned sidx = get_sector_index(sector_mask);
+ m_status[sidx] = status;
+ }
+ virtual unsigned get_last_access_time()
+ {
+ return m_line_last_access_time;
+ }
+ virtual void set_last_access_time(unsigned time, mem_access_sector_mask_t sector_mask)
+ {
+ unsigned sidx = get_sector_index(sector_mask);
+
+ m_last_sector_access_time[sidx] = time;
+ m_line_last_access_time = time;
+ }
+ virtual unsigned get_alloc_time()
+ {
+ return m_line_alloc_time;
+ }
+ virtual void set_ignore_on_fill(bool m_ignore, mem_access_sector_mask_t sector_mask)
+ {
+ unsigned sidx = get_sector_index(sector_mask);
+ m_ignore_on_fill_status[sidx] = m_ignore;
+ }
+ virtual void set_modified_on_fill(bool m_modified, mem_access_sector_mask_t sector_mask)
+ {
+ unsigned sidx = get_sector_index(sector_mask);
+ m_set_modified_on_fill[sidx] = m_modified;
+ }
+
+ virtual unsigned get_modified_size()
+ {
+ unsigned modified=0;
+ for(unsigned i =0; i< SECTOR_CHUNCK_SIZE; ++i) {
+ if (m_status[i] == MODIFIED)
+ modified++;
+ }
+ return modified * SECTOR_SIZE;
+ }
+
+private:
+ unsigned m_sector_alloc_time[SECTOR_CHUNCK_SIZE];
+ unsigned m_last_sector_access_time[SECTOR_CHUNCK_SIZE];
+ unsigned m_sector_fill_time[SECTOR_CHUNCK_SIZE];
+ unsigned m_line_alloc_time;
+ unsigned m_line_last_access_time;
+ unsigned m_line_fill_time;
+ cache_block_state m_status[SECTOR_CHUNCK_SIZE];
+ bool m_ignore_on_fill_status[SECTOR_CHUNCK_SIZE];
+ bool m_set_modified_on_fill[SECTOR_CHUNCK_SIZE];
+
+ unsigned get_sector_index(mem_access_sector_mask_t sector_mask)
+ {
+ assert(sector_mask.count() == 1);
+ for(unsigned i =0; i< SECTOR_CHUNCK_SIZE; ++i) {
+ if(sector_mask.to_ulong() & (1<<i))
+ return i;
+ }
+ }
};
enum replacement_policy_t {
@@ -115,12 +415,14 @@ enum allocation_policy_t {
enum write_allocate_policy_t {
NO_WRITE_ALLOCATE,
- WRITE_ALLOCATE
+ WRITE_ALLOCATE,
+ FETCH_ON_WRITE
};
enum mshr_config_t {
TEX_FIFO,
- ASSOC // normal cache
+ ASSOC, // normal cache
+ SECTOR_ASSOC // normal cache sends requests to high-level sector cache
};
enum set_index_function{
@@ -129,6 +431,11 @@ enum set_index_function{
CUSTOM_SET_FUNCTION
};
+enum cache_type{
+ NORMAL = 0,
+ SECTOR
+};
+
class cache_config {
public:
cache_config()
@@ -145,22 +452,33 @@ public:
{
cache_status= status;
assert( config );
- char rp, wp, ap, mshr_type, wap, sif;
+ char ct, rp, wp, ap, mshr_type, wap, sif;
- int ntok = sscanf(config,"%u:%u:%u,%c:%c:%c:%c:%c,%c:%u:%u,%u:%u,%u",
- &m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap, &wap,
+ int ntok = sscanf(config,"%c:%u:%u:%u,%c:%c:%c:%c:%c,%c:%u:%u,%u:%u,%u",
+ &ct, &m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap, &wap,
&sif,&mshr_type,&m_mshr_entries,&m_mshr_max_merge,
&m_miss_queue_size, &m_result_fifo_entries,
&m_data_port_width);
- if ( ntok < 11 ) {
+ if ( ntok < 12 ) {
if ( !strcmp(config,"none") ) {
m_disabled = true;
return;
}
exit_parse_error();
}
+
+ switch (ct) {
+ case 'N': m_cache_type = NORMAL; break;
+ case 'S': m_cache_type = SECTOR; break;
+ default: exit_parse_error();
+ }
+ switch (rp) {
+ case 'L': m_replacement_policy = LRU; break;
+ case 'F': m_replacement_policy = FIFO; break;
+ default: exit_parse_error();
+ }
switch (rp) {
case 'L': m_replacement_policy = LRU; break;
case 'F': m_replacement_policy = FIFO; break;
@@ -180,18 +498,24 @@ public:
default: exit_parse_error();
}
switch (mshr_type) {
- case 'F': m_mshr_type = TEX_FIFO; assert(ntok==13); break;
+ case 'F': m_mshr_type = TEX_FIFO; assert(ntok==14); break;
case 'A': m_mshr_type = ASSOC; break;
+ case 'S' : m_mshr_type = SECTOR_ASSOC; break;
default: exit_parse_error();
}
m_line_sz_log2 = LOGB2(m_line_sz);
m_nset_log2 = LOGB2(m_nset);
m_valid = true;
+ m_atom_sz = (m_cache_type == SECTOR)? SECTOR_SIZE : m_line_sz;
+ //For more details about difference between FETCH_ON_WRITE and WRITE VALIDAE policies
+ //Read: Jouppi, Norman P. "Cache write policies and performance". ISCA 93.
+ //WRITE_ALLOCATE is the old write policy in GPGPU-sim 3.x, that send WRITE and READ for every write request
switch(wap){
- case 'W': m_write_alloc_policy = WRITE_ALLOCATE; break;
case 'N': m_write_alloc_policy = NO_WRITE_ALLOCATE; break;
- default: exit_parse_error();
+ case 'W': m_write_alloc_policy = WRITE_ALLOCATE; break;
+ case 'F': m_write_alloc_policy = FETCH_ON_WRITE; break;
+ default: exit_parse_error();
}
// detect invalid configuration
@@ -208,6 +532,15 @@ public:
assert(0 && "Invalid cache configuration: Writeback cache cannot allocate new line on fill. ");
}
+ if(m_write_alloc_policy == FETCH_ON_WRITE && m_alloc_policy == ON_FILL)
+ {
+ assert(0 && "Invalid cache configuration: FETCH_ON_WRITE cannot work properly with ON_FILL policy. Cache must be ON_MISS. ");
+ }
+ if(m_cache_type == SECTOR)
+ {
+ assert(m_line_sz / SECTOR_SIZE == SECTOR_CHUNCK_SIZE && m_line_sz % SECTOR_SIZE == 0);
+ }
+
// default: port to data array width and granularity = line size
if (m_data_port_width == 0) {
m_data_port_width = m_line_sz;
@@ -227,6 +560,11 @@ public:
assert( m_valid );
return m_line_sz;
}
+ unsigned get_atom_sz() const
+ {
+ assert( m_valid );
+ return m_atom_sz;
+ }
unsigned get_num_lines() const
{
assert( m_valid );
@@ -265,6 +603,14 @@ public:
{
return addr & ~(m_line_sz-1);
}
+ new_addr_type mshr_addr( new_addr_type addr ) const
+ {
+ return addr & ~(m_atom_sz-1);
+ }
+ enum mshr_config_t get_mshr_type() const
+ {
+ return m_mshr_type;
+ }
FuncCache get_cache_status() {return cache_status;}
char *m_config_string;
char *m_config_stringPrefL1;
@@ -285,11 +631,13 @@ protected:
unsigned m_nset;
unsigned m_nset_log2;
unsigned m_assoc;
+ unsigned m_atom_sz;
enum replacement_policy_t m_replacement_policy; // 'L' = LRU, 'F' = FIFO
enum write_policy_t m_write_policy; // 'T' = write through, 'B' = write back, 'R' = read only
enum allocation_policy_t m_alloc_policy; // 'm' = allocate on miss, 'f' = allocate on fill
enum mshr_config_t m_mshr_type;
+ enum cache_type m_cache_type;
write_allocate_policy_t m_write_alloc_policy; // 'W' = Write allocate, 'N' = No write allocate
@@ -316,6 +664,7 @@ protected:
friend class data_cache;
friend class l1_cache;
friend class l2_cache;
+ friend class memory_sub_partition;
};
class l1d_cache_config : public cache_config{
@@ -340,15 +689,15 @@ public:
tag_array(cache_config &config, int core_id, int type_id );
~tag_array();
- 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 );
+ enum cache_request_status probe( new_addr_type addr, unsigned &idx, mem_fetch* mf ) const;
+ enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx, mem_fetch* mf );
+ enum cache_request_status access( new_addr_type addr, unsigned time, unsigned &idx, bool &wb, evicted_block_info &evicted, mem_fetch* mf );
- void fill( new_addr_type addr, unsigned time );
- void fill( unsigned idx, unsigned time );
+ void fill( new_addr_type addr, unsigned time, mem_fetch* mf );
+ void fill( unsigned idx, unsigned time, mem_fetch* mf );
unsigned size() const { return m_config.get_num_lines();}
- cache_block_t &get_block(unsigned idx) { return m_lines[idx];}
+ cache_block_t* get_block(unsigned idx) { return m_lines[idx];}
void flush(); // flash invalidate all entries
void new_window();
@@ -365,19 +714,20 @@ protected:
tag_array( cache_config &config,
int core_id,
int type_id,
- cache_block_t* new_lines );
+ cache_block_t** new_lines );
void init( int core_id, int type_id );
protected:
cache_config &m_config;
- cache_block_t *m_lines; /* nbanks x nset x assoc lines in total */
+ cache_block_t **m_lines; /* nbanks x nset x assoc lines in total */
unsigned m_access;
unsigned m_miss;
unsigned m_pending_hit; // number of cache miss that hit a line that is allocated but not filled
unsigned m_res_fail;
+ unsigned m_sector_miss;
// performance counters for calculating the amount of misses within a time window
unsigned m_prev_snapshot_access;
@@ -390,7 +740,7 @@ protected:
class mshr_table {
public:
- mshr_table( unsigned num_entries, unsigned max_merged )
+ mshr_table( unsigned num_entries, unsigned max_merged)
: m_num_entries(num_entries),
m_max_merged(max_merged)
#if (tr1_hash_map_ismap == 0)
@@ -414,6 +764,8 @@ public:
/// Returns next ready access
mem_fetch *next_access();
void display( FILE *fp ) const;
+ // Returns true if there is a pending read after write
+ bool is_read_after_write_pending(new_addr_type block_addr);
void check_mshr_parameters( unsigned num_entries, unsigned max_merged )
{
@@ -510,12 +862,14 @@ public:
cache_stats();
void clear();
void inc_stats(int access_type, int access_outcome);
+ void inc_fail_stats(int access_type, int fail_outcome);
enum cache_request_status select_stats_status(enum cache_request_status probe, enum cache_request_status access) const;
- unsigned &operator()(int access_type, int access_outcome);
- unsigned operator()(int access_type, int access_outcome) const;
+ unsigned &operator()(int access_type, int access_outcome, bool fail_outcome);
+ unsigned operator()(int access_type, int access_outcome, bool fail_outcome) const;
cache_stats operator+(const cache_stats &cs);
cache_stats &operator+=(const cache_stats &cs);
void print_stats(FILE *fout, const char *cache_name = "Cache_stats") const;
+ void print_fail_stats(FILE *fout, const char *cache_name = "Cache_fail_stats") const;
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;
@@ -523,8 +877,10 @@ public:
void sample_cache_port_utility(bool data_port_busy, bool fill_port_busy);
private:
bool check_valid(int type, int status) const;
+ bool check_fail_valid(int type, int fail) const;
std::vector< std::vector<unsigned> > m_stats;
+ std::vector< std::vector<unsigned> > m_fail_stats;
unsigned long long m_cache_port_available_cycles;
unsigned long long m_cache_data_port_busy_cycles;
@@ -543,6 +899,7 @@ public:
bool was_write_sent( const std::list<cache_event> &events );
bool was_read_sent( const std::list<cache_event> &events );
+bool was_writeallocate_sent( const std::list<cache_event> &events );
/// Baseline cache
/// Implements common functions for read_only_cache and data_cache
@@ -552,7 +909,7 @@ 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_mshrs(config.m_mshr_entries,config.m_mshr_max_merge),
m_bandwidth_management(config)
{
init( name, config, memport, status );
@@ -564,7 +921,7 @@ public:
enum mem_fetch_status status )
{
m_name = name;
- assert(config.m_mshr_type == ASSOC);
+ assert(config.m_mshr_type == ASSOC || config.m_mshr_type == SECTOR_ASSOC);
m_memport=memport;
m_miss_queue_status = status;
}
@@ -640,17 +997,24 @@ protected:
struct extra_mf_fields {
extra_mf_fields() { m_valid = false;}
- extra_mf_fields( new_addr_type a, unsigned i, unsigned d )
+ extra_mf_fields( new_addr_type a, new_addr_type ad, unsigned i, unsigned d, const cache_config& m_config)
{
m_valid = true;
m_block_addr = a;
+ m_addr = ad;
m_cache_index = i;
m_data_size = d;
+ pending_read = m_config.m_mshr_type == SECTOR_ASSOC? m_config.m_line_sz/SECTOR_SIZE : 0;
+
}
bool m_valid;
new_addr_type m_block_addr;
+ new_addr_type m_addr;
unsigned m_cache_index;
unsigned m_data_size;
+ //this variable is used when a load request generates multiple load transactions
+ //For example, a read request from non-sector L1 request sends a request to sector L2
+ unsigned pending_read;
};
typedef std::map<mem_fetch*,extra_mf_fields> extra_mf_fields_lookup;
@@ -668,7 +1032,7 @@ protected:
unsigned time, bool &do_miss, std::list<cache_event> &events, bool read_only, bool wa);
/// 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);
+ unsigned time, bool &do_miss, bool &wb, evicted_block_info &evicted, std::list<cache_event> &events, bool read_only, bool wa);
/// Sub-class containing all metadata for port bandwidth management
class bandwidth_management
@@ -760,8 +1124,9 @@ public:
// Set write miss function
switch(m_config.m_write_alloc_policy){
- case WRITE_ALLOCATE: m_wr_miss = &data_cache::wr_miss_wa; break;
case NO_WRITE_ALLOCATE: m_wr_miss = &data_cache::wr_miss_no_wa; break;
+ case WRITE_ALLOCATE: m_wr_miss = &data_cache::wr_miss_wa_naive; break;
+ case FETCH_ON_WRITE: m_wr_miss = &data_cache::wr_miss_wa_fetch_on_write; break;
default:
assert(0 && "Error: Must set valid cache write miss policy\n");
break; // Need to set a write miss function
@@ -870,12 +1235,26 @@ protected:
/// Sends read request, and possible write-back request,
// to lower level memory for a write miss with write-allocate
enum cache_request_status
- wr_miss_wa( new_addr_type addr,
- unsigned cache_index,
- mem_fetch *mf,
- unsigned time,
- std::list<cache_event> &events,
- enum cache_request_status status ); // write-allocate
+ wr_miss_wa_naive( new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status ); // write-allocate-send-write-and-read-request
+ enum cache_request_status
+ wr_miss_wa_fetch_on_write( new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status ); // write-allocate with read-fetch-only
+ enum cache_request_status
+ wr_miss_wa_write_validate( new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status ); // write-allocate that writes with no read fetch
enum cache_request_status
wr_miss_no_wa( new_addr_type addr,
unsigned cache_index,
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index b424d2c..eac92b4 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -294,12 +294,6 @@ void shader_core_config::reg_options(class OptionParser * opp)
option_parser_register(opp, "-gpgpu_shmem_warp_parts", OPT_INT32, &mem_warp_parts,
"Number of portions a warp is divided into for shared memory bank conflict check ",
"2");
- option_parser_register(opp, "-gpgpu_L1_warp_parts_cached", OPT_INT32, &L1_warp_parts_cached,
- "Number of portions a warp is divided into when the request is cached",
- "2");
- option_parser_register(opp, "-gpgpu_L1_warp_parts_cached", OPT_INT32, &L1_warp_parts_non_cached,
- "Number of portions a warp is divided into when the request is not cached",
- "4");
option_parser_register(opp, "-gpgpu_shmem_warp_parts", OPT_INT32, &mem_warp_parts,
"Number of portions a warp is divided into for shared memory bank conflict check ",
"2");
@@ -1013,6 +1007,8 @@ void gpgpu_sim::gpu_print_stat()
}
printf("\nTotal_core_cache_stats:\n");
core_cache_stats.print_stats(stdout, "Total_core_cache_stats_breakdown");
+ printf("\nTotal_core_cache_fail_stats:\n");
+ core_cache_stats.print_fail_stats(stdout, "Total_core_cache_fail_stats_breakdown");
shader_print_scheduler_stat( stdout, false );
m_shader_stats->print(stdout);
@@ -1057,6 +1053,8 @@ 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");
+ printf("L2_total_cache_reservation_fail_breakdown:\n");
+ l2_stats.print_fail_stats(stdout, "L2_cache_stats_fail_breakdown");
total_l2_css.print_port_stats(stdout, "L2_cache");
}
}
@@ -1436,7 +1434,8 @@ void gpgpu_sim::cycle()
for (unsigned i=0;i<m_memory_config->m_n_mem_sub_partition;i++) {
//move memory request from interconnect into memory partition (if not backed up)
//Note:This needs to be called in DRAM clock domain if there is no L2 cache in the system
- if ( m_memory_sub_partition[i]->full() ) {
+ //In the worst case, we may need to push SECTOR_CHUNCK_SIZE requests, so ensure you have enough buffer for them
+ if ( m_memory_sub_partition[i]->full(SECTOR_CHUNCK_SIZE) ) {
gpu_stall_dramfull++;
} else {
mem_fetch* mf = (mem_fetch*) icnt_pop( m_shader_config->mem2device(i) );
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index c5fc44e..f7323c5 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -343,6 +343,13 @@ void memory_sub_partition::cache_cycle( unsigned cycle )
mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
m_L2_icnt_queue->push(mf);
}else{
+ if(m_config->m_L2_config.m_write_alloc_policy == FETCH_ON_WRITE && mf->original_mf)
+ {
+ assert(mf->original_mf);
+ mf->original_mf->set_reply();
+ mf->original_mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
+ m_L2_icnt_queue->push(mf->original_mf);
+ }
m_request_tracker.erase(mf);
delete mf;
}
@@ -359,6 +366,7 @@ void memory_sub_partition::cache_cycle( unsigned cycle )
m_dram_L2_queue->pop();
}
} else if ( !m_L2_icnt_queue->full() ) {
+ if(mf->is_write() && mf->get_type() == WRITE_ACK)
mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
m_L2_icnt_queue->push(mf);
m_dram_L2_queue->pop();
@@ -402,6 +410,11 @@ void memory_sub_partition::cache_cycle( unsigned cycle )
m_icnt_L2_queue->pop();
}
} else if ( status != RESERVATION_FAIL ) {
+ if(mf->is_write() && m_config->m_L2_config.m_write_alloc_policy == FETCH_ON_WRITE && !was_writeallocate_sent(events)) {
+ mf->set_reply();
+ mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
+ m_L2_icnt_queue->push(mf);
+ }
// L2 cache accepted request
m_icnt_L2_queue->pop();
} else {
@@ -432,6 +445,11 @@ bool memory_sub_partition::full() const
return m_icnt_L2_queue->full();
}
+bool memory_sub_partition::full(unsigned size) const
+{
+ return m_icnt_L2_queue->is_avilable_size(size);
+}
+
bool memory_sub_partition::L2_dram_queue_empty() const
{
return m_L2_dram_queue->empty();
@@ -540,21 +558,90 @@ bool memory_sub_partition::busy() const
return !m_request_tracker.empty();
}
-void memory_sub_partition::push( mem_fetch* req, unsigned long long cycle )
+std::vector<mem_fetch*> memory_sub_partition::breakdown_request_to_sector_requests(mem_fetch* mf)
{
- if (req) {
- m_request_tracker.insert(req);
- m_stats->memlatstat_icnt2mem_pop(req);
- if( req->istexture() ) {
- m_icnt_L2_queue->push(req);
- req->set_status(IN_PARTITION_ICNT_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
- } else {
- rop_delay_t r;
- r.req = req;
- r.ready_cycle = cycle + m_config->rop_latency;
- m_rop.push(r);
- req->set_status(IN_PARTITION_ROP_DELAY,gpu_sim_cycle+gpu_tot_sim_cycle);
- }
+ std::vector<mem_fetch*> result;
+
+ if(mf->get_data_size() == SECTOR_SIZE && mf->get_access_sector_mask().count() == 1) {
+ result.push_back(mf);
+ } else if (mf->get_data_size() == 128 || mf->get_data_size() == 64) {
+ //We only accept 32, 64 and 128 bytes reqs
+ unsigned start=0, end=0;
+ if(mf->get_data_size() == 128) {
+ start=0; end=3;
+ } else if (mf->get_data_size() == 64 && mf->get_access_sector_mask().to_string() == "1100") {
+ start=2; end=3;
+ } else if (mf->get_data_size() == 64 && mf->get_access_sector_mask().to_string() == "0011") {
+ start=0; end=1;
+ } else if (mf->get_data_size() == 64 && (mf->get_access_sector_mask().to_string() == "1111" || mf->get_access_sector_mask().to_string() == "0000")) {
+ if(mf->get_addr() % 128 == 0) {
+ start=0; end=1;
+ } else {
+ start=2; end=3;
+ }
+ } else
+ {
+ printf("Invalid sector received, address = 0x%06x, sector mask = %s, data size = %d",
+ mf->get_addr(), mf->get_access_sector_mask(), mf->get_data_size(), mf->get_data_size());
+ assert(0 && "Undefined sector mask is received");
+ }
+
+ std::bitset<SECTOR_SIZE*SECTOR_CHUNCK_SIZE> byte_sector_mask;
+ byte_sector_mask.reset();
+ for(unsigned k=start*SECTOR_SIZE; k< SECTOR_SIZE; ++k)
+ byte_sector_mask.set(k);
+
+ for(unsigned j=start, i=0; j<= end ; ++j, ++i){
+
+ const mem_access_t *ma = new mem_access_t( mf->get_access_type(),
+ mf->get_addr() + SECTOR_SIZE*i,
+ SECTOR_SIZE,
+ mf->is_write(),
+ mf->get_access_warp_mask(),
+ mf->get_access_byte_mask() & byte_sector_mask,
+ std::bitset<SECTOR_CHUNCK_SIZE>().set(j));
+
+ mem_fetch *n_mf = new mem_fetch( *ma,
+ NULL,
+ mf->get_ctrl_size(),
+ mf->get_wid(),
+ mf->get_sid(),
+ mf->get_tpc(),
+ mf->get_mem_config(),
+ mf);
+
+ result.push_back(n_mf);
+ byte_sector_mask <<= SECTOR_SIZE;
+ }
+ } else assert(0 && "Undefined data size is received");
+
+ return result;
+}
+
+void memory_sub_partition::push( mem_fetch* m_req, unsigned long long cycle )
+{
+ if (m_req) {
+ std::vector<mem_fetch*> reqs;
+ if(m_config->m_L2_config.m_cache_type == SECTOR)
+ reqs = breakdown_request_to_sector_requests(m_req);
+ else
+ reqs.push_back(m_req);
+
+ for(unsigned i=0; i<reqs.size(); ++i) {
+ mem_fetch* req = reqs[i];
+ m_request_tracker.insert(req);
+ m_stats->memlatstat_icnt2mem_pop(req);
+ if( req->istexture() ) {
+ m_icnt_L2_queue->push(req);
+ req->set_status(IN_PARTITION_ICNT_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
+ } else {
+ rop_delay_t r;
+ r.req = req;
+ r.ready_cycle = cycle + m_config->rop_latency;
+ m_rop.push(r);
+ req->set_status(IN_PARTITION_ROP_DELAY,gpu_sim_cycle+gpu_tot_sim_cycle);
+ }
+ }
}
}
diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h
index 3df54b1..2cc0e76 100644
--- a/src/gpgpu-sim/l2cache.h
+++ b/src/gpgpu-sim/l2cache.h
@@ -154,6 +154,7 @@ public:
void cache_cycle( unsigned cycle );
bool full() const;
+ bool full(unsigned size) const;
void push( class mem_fetch* mf, unsigned long long clock_cycle );
class mem_fetch* pop();
class mem_fetch* top();
@@ -207,6 +208,8 @@ private:
std::set<mem_fetch*> m_request_tracker;
friend class L2interface;
+
+ std::vector<mem_fetch*> breakdown_request_to_sector_requests(mem_fetch* mf);
};
class L2interface : public mem_fetch_interface {
diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc
index 580c051..b8e918f 100644
--- a/src/gpgpu-sim/mem_fetch.cc
+++ b/src/gpgpu-sim/mem_fetch.cc
@@ -39,7 +39,8 @@ mem_fetch::mem_fetch( const mem_access_t &access,
unsigned wid,
unsigned sid,
unsigned tpc,
- const class memory_config *config )
+ const class memory_config *config,
+ mem_fetch *m_original_mf)
{
m_request_uid = sm_next_mf_request_uid++;
m_access = access;
@@ -61,6 +62,7 @@ mem_fetch::mem_fetch( const mem_access_t &access,
m_status_change = gpu_sim_cycle + gpu_tot_sim_cycle;
m_mem_config = config;
icnt_flit_size = config->icnt_flit_size;
+ original_mf = m_original_mf;
}
mem_fetch::~mem_fetch()
diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h
index db4a8e9..76e7419 100644
--- a/src/gpgpu-sim/mem_fetch.h
+++ b/src/gpgpu-sim/mem_fetch.h
@@ -55,7 +55,8 @@ public:
unsigned wid,
unsigned sid,
unsigned tpc,
- const class memory_config *config );
+ const class memory_config *config,
+ mem_fetch *original_mf = NULL);
~mem_fetch();
void set_status( enum mem_fetch_status status, unsigned long long cycle );
@@ -113,6 +114,7 @@ public:
const memory_config *get_mem_config(){return m_mem_config;}
unsigned get_num_flits(bool simt_to_mem);
+ mem_fetch* original_mf;
private:
// request source information
unsigned m_request_uid;