diff options
| author | Mahmoud <[email protected]> | 2019-07-29 21:18:06 -0400 |
|---|---|---|
| committer | Mahmoud <[email protected]> | 2019-07-29 21:18:06 -0400 |
| commit | 5875fda72d4402413bc5c04ee5ec15085ff2b90a (patch) | |
| tree | c920268d899df331e1a5e451a35133eaff7ca341 /src/gpgpu-sim/gpu-cache.cc | |
| parent | c05dc90da35fc2bd9dd42da9626bf3a60e2c9e8d (diff) | |
| parent | 21d937256fbca004c926531cfef1adefcedeef91 (diff) | |
Merge branch 'dev' of https://github.com/mkhairy/gpgpu-sim-private into dev-purdue-integration-trace
Diffstat (limited to 'src/gpgpu-sim/gpu-cache.cc')
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 294 |
1 files changed, 226 insertions, 68 deletions
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index 75ec00a..370f6e6 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -29,7 +29,6 @@ #include "stat-tool.h" #include <assert.h> -#define MAX_DEFAULT_CACHE_SIZE_MULTIBLIER 4 // used to allocate memory that is large enough to adapt the changes in cache size across kernels const char * cache_request_status_str(enum cache_request_status status) @@ -71,6 +70,7 @@ unsigned l1d_cache_config::set_index(new_addr_type addr) const{ switch(m_set_index_function){ case FERMI_HASH_SET_FUNCTION: + case BITWISE_XORING_FUNCTION: /* * Set Indexing function from "A Detailed GPU Cache Model Based on Reuse Distance Theory" * Cedric Nugteren et al. @@ -164,7 +164,7 @@ 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(); + unsigned cache_lines_num = m_config.get_max_num_lines(); for(unsigned i=0; i<cache_lines_num; ++i) delete m_lines[i]; delete[] m_lines; @@ -191,7 +191,7 @@ tag_array::tag_array( cache_config &config, : m_config( config ) { //assert( m_config.m_write_policy == READ_ONLY ); Old assert - unsigned cache_lines_num = MAX_DEFAULT_CACHE_SIZE_MULTIBLIER*config.get_num_lines(); + unsigned cache_lines_num = config.get_max_num_lines(); m_lines = new cache_block_t*[cache_lines_num]; if(config.m_cache_type == NORMAL) { @@ -222,23 +222,41 @@ void tag_array::init( int core_id, int type_id ) m_prev_snapshot_pending_hit = 0; m_core_id = core_id; m_type_id = type_id; + is_used = false; } +void tag_array::add_pending_line(mem_fetch *mf){ + assert(mf); + new_addr_type addr = m_config.block_addr(mf->get_addr()); + line_table::const_iterator i = pending_lines.find(addr); + if ( i == pending_lines.end() ) { + pending_lines[addr] = mf->get_inst().get_uid(); + } +} + +void tag_array::remove_pending_line(mem_fetch *mf){ + assert(mf); + new_addr_type addr = m_config.block_addr(mf->get_addr()); + line_table::const_iterator i = pending_lines.find(addr); + if ( i != pending_lines.end() ) { + pending_lines.erase(addr); + } +} -enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, mem_fetch* mf) const { +enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, mem_fetch* mf, bool probe_mode) const { mem_access_sector_mask_t mask = mf->get_access_sector_mask(); - return probe(addr, idx, mask); + return probe(addr, idx, mask, probe_mode, mf); } -enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, mem_access_sector_mask_t mask) const { +enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, mem_access_sector_mask_t mask, bool probe_mode, 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); unsigned invalid_line = (unsigned)-1; unsigned valid_line = (unsigned)-1; - unsigned valid_timestamp = (unsigned)-1; + unsigned long long valid_timestamp = (unsigned)-1; bool all_reserved = true; @@ -301,6 +319,16 @@ enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx, m idx = valid_line; } else abort(); // if an unreserved block exists, it is either invalid or replaceable + + if(probe_mode && m_config.is_streaming()){ + line_table::const_iterator i = pending_lines.find(m_config.block_addr(addr)); + assert(mf); + if ( !mf->is_write() && i != pending_lines.end() ) { + if(i->second != mf->get_inst().get_uid()) + return SECTOR_MISS; + } + } + return MISS; } @@ -316,6 +344,7 @@ enum cache_request_status tag_array::access( new_addr_type addr, unsigned time, 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++; + is_used = true; shader_cache_access_log(m_core_id, m_type_id, 0); // log accesses to cache enum cache_request_status status = probe(addr,idx,mf); switch (status) { @@ -382,13 +411,32 @@ void tag_array::fill( unsigned index, unsigned time, mem_fetch* mf) m_lines[index]->fill(time, mf->get_access_sector_mask()); } + +//TODO: we need write back the flushed data to the upper level void tag_array::flush() { + if(!is_used) + return; + for (unsigned i=0; i < m_config.get_num_lines(); i++) if(m_lines[i]->is_modified_line()) { for(unsigned j=0; j < SECTOR_CHUNCK_SIZE; j++) m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j)) ; } + + is_used = false; +} + +void tag_array::invalidate() +{ + if(!is_used) + return; + + for (unsigned i=0; i < m_config.get_num_lines(); i++) + for(unsigned j=0; j < SECTOR_CHUNCK_SIZE; j++) + m_lines[i]->set_status(INVALID, mem_access_sector_mask_t().set(j)) ; + + is_used = false; } float tag_array::windowed_miss_rate( ) const @@ -552,9 +600,11 @@ void mshr_table::display( FILE *fp ) const{ /***************************************************************** Caches *****************************************************************/ cache_stats::cache_stats(){ m_stats.resize(NUM_MEM_ACCESS_TYPE); + m_stats_pw.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_stats_pw[i].resize(NUM_CACHE_REQUEST_STATUS, 0); m_fail_stats[i].resize(NUM_CACHE_RESERVATION_FAIL_STATUS, 0); } m_cache_port_available_cycles = 0; @@ -575,6 +625,15 @@ void cache_stats::clear(){ m_cache_fill_port_busy_cycles = 0; } +void cache_stats::clear_pw(){ + /// + /// Zero out per-window cache statistics + /// + for(unsigned i=0; i<NUM_MEM_ACCESS_TYPE; ++i){ + std::fill(m_stats_pw[i].begin(), m_stats_pw[i].end(), 0); + } +} + void cache_stats::inc_stats(int access_type, int access_outcome){ /// /// Increment the stat corresponding to (access_type, access_outcome) by 1. @@ -584,6 +643,16 @@ void cache_stats::inc_stats(int access_type, int access_outcome){ m_stats[access_type][access_outcome]++; } + +void cache_stats::inc_stats_pw(int access_type, int access_outcome){ + /// + /// Increment the corresponding per-window cache stat + /// + if(!check_valid(access_type, access_outcome)) + assert(0 && "Unknown cache access type or access outcome"); + m_stats_pw[access_type][access_outcome]++; +} + void cache_stats::inc_fail_stats(int access_type, int fail_outcome){ if(!check_fail_valid(access_type, fail_outcome)) @@ -606,7 +675,7 @@ enum cache_request_status cache_stats::select_stats_status(enum cache_request_st return access; } -unsigned &cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome){ +unsigned long long &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 @@ -625,7 +694,7 @@ unsigned &cache_stats::operator()(int access_type, int access_outcome, bool fail } } -unsigned cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome) const{ +unsigned long long cache_stats::operator()(int access_type, int access_outcome, bool fail_outcome) const{ /// /// Const accessor into m_stats. /// @@ -670,6 +739,9 @@ cache_stats &cache_stats::operator+=(const cache_stats &cs){ for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){ m_stats[type][status] += cs(type, status, false); } + for(unsigned status=0; status<NUM_CACHE_REQUEST_STATUS; ++status){ + m_stats_pw[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); } @@ -687,23 +759,24 @@ 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::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) { - fprintf(fout, "\t%s[%s][%s] = %u\n", + fprintf(fout, "\t%s[%s][%s] = %llu\n", m_cache_name.c_str(), 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", + fprintf(fout, "\t%s[%s][%s] = %llu\n", m_cache_name.c_str(), mem_access_type_str((enum mem_access_type)type), "TOTAL_ACCESS", @@ -740,13 +813,13 @@ void cache_sub_stats::print_port_stats(FILE *fout, const char *cache_name) const 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{ +unsigned long long 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. /// "access_type" is an array of "num_access_type" mem_access_types. /// "access_status" is an array of "num_access_status" cache_request_statuses. /// - unsigned total=0; + unsigned long long total=0; for(unsigned type =0; type < num_access_type; ++type){ for(unsigned status=0; status < num_access_status; ++status){ if(!check_valid((int)access_type[type], (int)access_status[status])) @@ -756,6 +829,7 @@ unsigned cache_stats::get_stats(enum mem_access_type *access_type, unsigned num_ } return total; } + void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{ /// /// Overwrites "css" with the appropriate statistics from this cache. @@ -786,6 +860,55 @@ void cache_stats::get_sub_stats(struct cache_sub_stats &css) const{ css = t_css; } +void cache_stats::get_sub_stats_pw(struct cache_sub_stats_pw &css) const{ + /// + /// Overwrites "css" with the appropriate statistics from this cache. + /// + struct cache_sub_stats_pw t_css; + t_css.clear(); + + 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 == SECTOR_MISS || status == HIT_RESERVED) + t_css.accesses += m_stats_pw[type][status]; + + if(status == HIT){ + if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){ + t_css.read_hits += m_stats_pw[type][status]; + } else if(type == GLOBAL_ACC_W){ + t_css.write_hits += m_stats_pw[type][status]; + } + } + + if(status == MISS || status == SECTOR_MISS){ + if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){ + t_css.read_misses += m_stats_pw[type][status]; + } else if(type == GLOBAL_ACC_W){ + t_css.write_misses += m_stats_pw[type][status]; + } + } + + if(status == HIT_RESERVED){ + if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){ + t_css.read_pending_hits += m_stats_pw[type][status]; + } else if(type == GLOBAL_ACC_W){ + t_css.write_pending_hits += m_stats_pw[type][status]; + } + } + + if(status == RESERVATION_FAIL){ + if(type == GLOBAL_ACC_R || type == CONST_ACC_R || type == INST_ACC_R){ + t_css.read_res_fails += m_stats_pw[type][status]; + } else if(type == GLOBAL_ACC_W){ + t_css.write_res_fails += m_stats_pw[type][status]; + } + } + } + } + + css = t_css; +} + bool cache_stats::check_valid(int type, int status) const{ /// /// Verify a valid access_type/access_status @@ -907,8 +1030,8 @@ void baseline_cache::cycle(){ 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(mf->get_original_mf()); + extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf->get_original_mf()); assert( e != m_extra_mf_fields.end() ); e->second.pending_read--; @@ -918,7 +1041,7 @@ void baseline_cache::fill(mem_fetch *mf, unsigned time){ return; } else { mem_fetch *temp = mf; - mf = mf->original_mf; + mf = mf->get_original_mf(); delete temp; } } @@ -930,8 +1053,11 @@ void baseline_cache::fill(mem_fetch *mf, unsigned time){ 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,mf); - else if ( m_config.m_alloc_policy == ON_FILL ) + else if ( m_config.m_alloc_policy == ON_FILL ) { m_tag_array->fill(e->second.m_block_addr,time,mf); + if(m_config.is_streaming()) + m_tag_array->remove_pending_line(mf); + } else abort(); bool has_atomic = false; m_mshrs.mark_ready(e->second.m_block_addr, has_atomic); @@ -985,6 +1111,7 @@ void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_a 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,mf); @@ -992,6 +1119,9 @@ void baseline_cache::send_read_request(new_addr_type addr, new_addr_type block_a m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf); m_mshrs.add(mshr_addr,mf); + if(m_config.is_streaming() && m_config.m_cache_type == SECTOR){ + m_tag_array->add_pending_line(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( mshr_addr ); @@ -1162,52 +1292,7 @@ data_cache::wr_miss_wa_fetch_on_write( new_addr_type addr, 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()); - - - //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 m_status = m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf); - assert(m_status != HIT); - cache_block_t* block = m_tag_array->get_block(cache_index); - block->set_status(MODIFIED, mf->get_access_sector_mask()); - if(m_status == HIT_RESERVED) { - block->set_ignore_on_fill(true, mf->get_access_sector_mask()); - block->set_modified_on_fill(true, mf->get_access_sector_mask()); - } - - if(mf->get_access_byte_mask().count() == m_config.get_atom_sz()) - { - block->set_m_readable(true, mf->get_access_sector_mask()); - } else - { - block->set_m_readable(false, mf->get_access_sector_mask()); - } - - if( m_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; - - /*new_addr_type block_addr = m_config.block_addr(addr); + new_addr_type block_addr = m_config.block_addr(addr); new_addr_type mshr_addr = m_config.mshr_addr(mf->get_addr()); if(mf->get_access_byte_mask().count() == m_config.get_atom_sz()) @@ -1316,7 +1401,59 @@ data_cache::wr_miss_wa_fetch_on_write( new_addr_type addr, return MISS; } return RESERVATION_FAIL; - }*/ + } +} + +enum cache_request_status +data_cache::wr_miss_wa_lazy_fetch_on_read( 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()); + + + //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 m_status = m_tag_array->access(block_addr,time,cache_index,wb,evicted,mf); + assert(m_status != HIT); + cache_block_t* block = m_tag_array->get_block(cache_index); + block->set_status(MODIFIED, mf->get_access_sector_mask()); + if(m_status == HIT_RESERVED) { + block->set_ignore_on_fill(true, mf->get_access_sector_mask()); + block->set_modified_on_fill(true, mf->get_access_sector_mask()); + } + + if(mf->get_access_byte_mask().count() == m_config.get_atom_sz()) + { + block->set_m_readable(true, mf->get_access_sector_mask()); + } else + { + block->set_m_readable(false, mf->get_access_sector_mask()); + } + + if( m_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; } /// No write-allocate miss: Simply send write request to lower level memory @@ -1439,6 +1576,7 @@ read_only_cache::access( new_addr_type addr, } m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status)); + m_stats.inc_stats_pw(mf->get_access_type(), m_stats.select_stats_status(status, cache_status)); return cache_status; } @@ -1508,11 +1646,13 @@ data_cache::access( new_addr_type addr, 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, mf ); + = m_tag_array->probe( block_addr, cache_index, mf, true); 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(), m_stats.select_stats_status(probe_status, access_status)); + m_stats.inc_stats_pw(mf->get_access_type(), + m_stats.select_stats_status(probe_status, access_status)); return access_status; } @@ -1565,7 +1705,7 @@ enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf, if ( status == MISS ) { // we need to send a memory request... unsigned rob_index = m_rob.push( rob_entry(cache_index, mf, block_addr) ); - m_extra_mf_fields[mf] = extra_mf_fields(rob_index); + m_extra_mf_fields[mf] = extra_mf_fields(rob_index, m_config); mf->set_data_size(m_config.get_line_sz()); m_tags.fill(cache_index,time,mf); // mark block as valid m_request_fifo.push(mf); @@ -1577,6 +1717,7 @@ enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf, cache_status = HIT_RESERVED; } m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status)); + m_stats.inc_stats_pw(mf->get_access_type(), m_stats.select_stats_status(status, cache_status)); return cache_status; } @@ -1620,6 +1761,23 @@ void tex_cache::cycle(){ /// Place returning cache block into reorder buffer void tex_cache::fill( mem_fetch *mf, unsigned time ) { + if(m_config.m_mshr_type == SECTOR_TEX_FIFO) { + assert(mf->get_original_mf()); + extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf->get_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->get_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 ); |
