summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTayler Hetherington <[email protected]>2012-09-28 10:37:26 -0800
committerAndrew Boktor <[email protected]>2014-08-14 13:49:21 -0700
commit495cfab5e38d80c8daddf170dce84f3e2d08f537 (patch)
tree7bf683cc9bf24130bd5b61062ce26e4469f16566 /src
parent3bcf37cfe0514e4ee13fcab94778440b17124b28 (diff)
gpu-cache revision #3. Now adding in function pointers for l1/l2 cache access functions. Removes the multiple long flaky branches in the access functions (caused by multiple config options) and replaces them with a single function that is set in the constructor to reflect the current configuration.
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 14198]
Diffstat (limited to 'src')
-rw-r--r--src/gpgpu-sim/gpu-cache.cc305
-rw-r--r--src/gpgpu-sim/gpu-cache.h58
2 files changed, 208 insertions, 155 deletions
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index 23e6ede..634ad61 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -383,22 +383,86 @@ void data_cache::send_write_request(mem_fetch *mf, cache_event request, unsigned
mf->set_status(m_miss_queue_status,time);
}
-/// Sends read request, and possible write-back request, to lower level memory for a write miss with write-allocate
-bool data_cache::send_write_allocate(mem_fetch *mf, new_addr_type addr, new_addr_type block_addr, unsigned cache_index, unsigned time, std::list<cache_event> &events){
+
+/****** Write-hit functions (Set by config file) ******/
+
+/// 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 ){
+ 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;
+
+ 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 ){
+ if(miss_queue_full(0))
+ return RESERVATION_FAIL; // cannot handle request this cycle
+
+ // generate a write-through
+ send_write_request(mf, 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 ){
+ if(miss_queue_full(0))
+ 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);
+
+ // Invalidate block
+ block.m_status = INVALID;
+ return HIT;
+}
+
+/// Global write-evict, local write-back: Useful for private caches
+enum cache_request_status data_cache::wr_hit_global_we_local_wb(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events ){
+ bool evict = (mf->get_access_type() == GLOBAL_ACC_W); // evict a line that hits on global memory write
+ if(evict)
+ return wr_hit_wb(addr, cache_index, mf, time, events);
+ else
+ return wr_hit_we(addr, cache_index, mf, time, events);
+}
+
+/****** Write-miss functions (Set by config file) ******/
+
+/// 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, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events) {
+
+ new_addr_type block_addr = m_config.block_addr(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);
+ if(miss_queue_full(2) || (!(mshr_hit && mshr_avail) && !(!mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size))))
+ return RESERVATION_FAIL;
+
+ send_write_request(mf, 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( L2_WR_ALLOC_R,
- mf->get_addr(),
- mf->get_data_size(),
- false, // Now performing a read
- mf->get_access_warp_mask(),
- mf->get_access_byte_mask() );
+ mf->get_addr(),
+ mf->get_data_size(),
+ false, // Now performing a read
+ mf->get_access_warp_mask(),
+ mf->get_access_byte_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());
+ NULL,
+ mf->get_ctrl_size(),
+ mf->get_wid(),
+ mf->get_sid(),
+ mf->get_tpc(),
+ mf->get_mem_config());
bool do_miss = false;
bool wb = false;
@@ -413,192 +477,133 @@ bool data_cache::send_write_allocate(mem_fetch *mf, new_addr_type addr, new_addr
wb->set_status(m_miss_queue_status,time);
}
if( do_miss )
- return true;
- return false;
+ return MISS;
+ return RESERVATION_FAIL;
}
-/// Marks block as MODIFIED and updates block LRU
-void data_cache::write_back_hit(new_addr_type block_addr, unsigned time, unsigned cache_index){
- 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;
+/// 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, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events ){
+ if(miss_queue_full(0))
+ 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);
+ return MISS;
}
-/// Marks block as INVALID and sends write request to lower level memory
-bool data_cache::do_write_evict(mem_fetch *mf, unsigned time, unsigned cache_index, std::list<cache_event> &events){
- if(miss_queue_full(0))
- return false; // cannot handle request this cycle
+/****** Read hit functions (Set by config file) ******/
+
+/// Baseline read hit: Update LRU status of block. Special case for atomic instructions -> Mark block as modified
+enum cache_request_status data_cache::rd_hit_base(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events ){
+ new_addr_type block_addr = m_config.block_addr(addr);
+ m_tag_array.access(block_addr,time,cache_index);
+ if(mf->isatomic()){ // Atomics treated as global read/write requests - Perform read, mark line as MODIFIED
+ 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
+ }
+ return HIT;
+}
+
+/****** Read miss functions (Set by config file) ******/
+
+/// Baseline read miss: Send read request to lower level memory, perform write-back as necessary
+enum cache_request_status data_cache::rd_miss_base(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events ){
+ if(miss_queue_full(1))
+ return RESERVATION_FAIL; // cannot handle request this cycle (might need to generate two requests)
- // 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);
+ new_addr_type block_addr = m_config.block_addr(addr);
+ bool do_miss = false;
+ bool wb = false;
+ cache_block_t evicted;
+ send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, evicted, events, false, false);
- // Invalidate block
- block.m_status = INVALID;
- return true;
+ if(wb){
+ mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr, L1_WRBK_ACC,m_config.get_line_sz(),true);
+ send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
+ }
+ if( do_miss )
+ return MISS;
+ return RESERVATION_FAIL;
}
/// Access cache for read_only_cache: returns RESERVATION_FAIL if request could not be accepted (for any reason)
enum cache_request_status read_only_cache::access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ) {
- assert( mf->get_data_size() <= m_config.get_line_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);
- if ( status == HIT ) {
- m_tag_array.access(block_addr,time,cache_index); // update LRU state
- return HIT;
- }
- if ( status != RESERVATION_FAIL ) {
- if(!miss_queue_full(0)){
+ assert( mf->get_data_size() <= m_config.get_line_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);
+ if ( status == HIT ) {
+ m_tag_array.access(block_addr,time,cache_index); // update LRU state
+ return HIT;
+ }else if ( status != RESERVATION_FAIL ) {
+ if(!miss_queue_full(0)){
bool do_miss=false;
send_read_request(addr, block_addr, cache_index, mf, time, do_miss, events, true, false);
if(do_miss)
return MISS;
- }
- }
- return RESERVATION_FAIL;
+ }
+ }
+ return RESERVATION_FAIL;
}
/// This is meant to model the first level data cache in Fermi.
-/// It is write-evict (global) or write-back (local) at the granularity of individual blocks
+/// It is write-evict (global) or write-back (local) at the granularity of individual blocks (Set by GPGPU-Sim configuration file)
/// (the policy used in fermi according to the CUDA manual)
enum cache_request_status l1_cache::access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ){
assert( mf->get_data_size() <= m_config.get_line_sz());
bool wr = mf->get_is_write();
- bool isatomic = mf->isatomic();
- enum mem_access_type type = mf->get_access_type();
+ 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);
- bool evict = (type == GLOBAL_ACC_W); // evict a line that hits on global memory 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);
-
- if(wr){ // Write
- assert(m_config.m_write_policy != READ_ONLY);
+ // Each function pointer (m_rd/wr_hit/miss) is set in the data_cache constructor to reflect the corresponding cache configuration options
+ if(wr){ // Write
if(status == HIT){
- if(m_config.m_write_policy == WRITE_BACK && !evict){
- write_back_hit(block_addr, time, cache_index);
- }else if(m_config.m_write_policy == WRITE_EVICT || evict){
- if(!do_write_evict(mf, time, cache_index, events))
- return RESERVATION_FAIL;
- }
- return HIT;
+ return (this->*m_wr_hit)(addr, cache_index, mf, time, events);
}else if ( status != RESERVATION_FAIL ) {
- if(miss_queue_full(0))
- 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);
- return MISS;
+ return (this->*m_wr_miss)(addr, cache_index, mf, time, events);
}
}else{ // Read
- if(status == HIT){ // Read hit: Update LRU state
- m_tag_array.access(block_addr,time,cache_index);
- if(isatomic){ // Atomics treated as global read/write requests - Perform read, mark line as MODIFIED
- assert(type == GLOBAL_ACC_R);
- cache_block_t &block = m_tag_array.get_block(cache_index);
- block.m_status = MODIFIED; // mark line as dirty
- }
- return HIT;
+ if(status == HIT){
+ return (this->*m_rd_hit)(addr, cache_index, mf, time, events);
}else if ( status != RESERVATION_FAIL ) {
- if(miss_queue_full(1))
- return RESERVATION_FAIL; // cannot handle request this cycle (might need to generate two requests)
-
- bool do_miss = false;
- bool wb = false;
- cache_block_t evicted;
- send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, evicted, events, false, false);
-
- if(wb){
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr, L1_WRBK_ACC,m_config.get_line_sz(),true);
- send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
- }
- if( do_miss )
- return MISS;
+ return (this->*m_rd_miss)(addr, cache_index, mf, time, events);
}
}
return RESERVATION_FAIL;
}
/// Models second level shared cache with global write-back and write-allocate policies
+/// Currently the same as l1_cache, but separated to allow for different implementations
enum cache_request_status l2_cache::access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ){
assert( mf->get_data_size() <= m_config.get_line_sz());
bool wr = mf->get_is_write();
- bool isatomic = mf->isatomic();
- enum mem_access_type type = mf->get_access_type();
-
- 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);
+ 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);
- if(wr){ // Write
- assert(m_config.m_write_policy != READ_ONLY);
+ // Each function pointer (m_rd/wr_hit/miss) is set in the data_cache constructor to reflect the corresponding cache configuration options
+ if(wr){ // Write
if(status == HIT){
- if(m_config.m_write_policy == WRITE_BACK){
- write_back_hit(block_addr, time, cache_index);
- }else if(m_config.m_write_policy == WRITE_EVICT){
- assert(0);
- if(!do_write_evict(mf, time, cache_index, events))
- return RESERVATION_FAIL;
- }
- return HIT;
+ return (this->*m_wr_hit)(addr, cache_index, mf, time, events);
}else if ( status != RESERVATION_FAIL ) {
- if(m_config.m_write_alloc_policy == WRITE_ALLOCATE){
- // 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);
- if(miss_queue_full(2) || (!(mshr_hit && mshr_avail) && !(!mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size))))
- return RESERVATION_FAIL;
-
- send_write_request(mf, 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;
- }else{
- if(miss_queue_full(0))
- 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);
- }
- return MISS;
+ return (this->*m_wr_miss)(addr, cache_index, mf, time, events);
}
}else{ // Read
- if(status == HIT){ // Read hit: Update LRU state
- m_tag_array.access(block_addr,time,cache_index);
- if(isatomic){ // Atomics treated as global read/write requests - Perform read, mark line as MODIFIED
- assert(type == GLOBAL_ACC_R);
- // treated as write back...
- cache_block_t &block = m_tag_array.get_block(cache_index);
- block.m_status = MODIFIED; // mark line as dirty
- }
- return HIT;
+ if(status == HIT){
+ return (this->*m_rd_hit)(addr, cache_index, mf, time, events);
}else if ( status != RESERVATION_FAIL ) {
- if(miss_queue_full(1))
- return RESERVATION_FAIL; // cannot handle request this cycle (might need to generate two requests)
-
- bool do_miss = false;
- bool wb = false;
- cache_block_t evicted;
- send_read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, evicted, events, false, false);
-
- if(wb){
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr, L1_WRBK_ACC,m_config.get_line_sz(),true);
- send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
- }
- if( do_miss )
- return MISS;
+ return (this->*m_rd_miss)(addr, cache_index, mf, time, events);
}
}
return RESERVATION_FAIL;
}
-
/// Access function for tex_cache
/// return values: RESERVATION_FAIL if request could not be accepted
/// otherwise returns HIT_RESERVED or MISS; NOTE: *never* returns HIT
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 431760a..86183d3 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -98,7 +98,8 @@ enum write_policy_t {
READ_ONLY,
WRITE_BACK,
WRITE_THROUGH,
- WRITE_EVICT
+ WRITE_EVICT,
+ LOCAL_WB_GLOBAL_WT
};
enum allocation_policy_t {
@@ -152,6 +153,7 @@ public:
case 'B': m_write_policy = WRITE_BACK; break;
case 'T': m_write_policy = WRITE_THROUGH; break;
case 'E': m_write_policy = WRITE_EVICT; break;
+ case 'L': m_write_policy = LOCAL_WB_GLOBAL_WT; break;
default: exit_parse_error();
}
switch (ap) {
@@ -441,6 +443,29 @@ public:
: baseline_cache(name,config,core_id,type_id,memport,status)
{
m_memfetch_creator=mfcreator;
+
+ // Set read hit function
+ m_rd_hit = &data_cache::rd_hit_base;
+
+ // Set read miss function
+ m_rd_miss = &data_cache::rd_miss_base;
+
+ // Set write hit function
+ switch(m_config.m_write_policy){
+ case READ_ONLY: assert(0 && "Error: Writable Data_cache set as READ_ONLY\n"); break; // READ_ONLY is now a separate cache class, config is deprecated
+ case WRITE_BACK: m_wr_hit = &data_cache::wr_hit_wb; break;
+ case WRITE_THROUGH: m_wr_hit = &data_cache::wr_hit_wt; break;
+ case WRITE_EVICT: m_wr_hit = &data_cache::wr_hit_we; break;
+ case LOCAL_WB_GLOBAL_WT: m_wr_hit = &data_cache::wr_hit_global_we_local_wb; break;
+ default: assert(0 && "Error: Must set valid cache write policy\n"); break; // Need to set a write hit function
+ }
+
+ // 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;
+ default: assert(0 && "Error: Must set valid cache write miss policy\n"); break; // Need to set a write miss function
+ }
}
protected:
@@ -449,12 +474,34 @@ protected:
// Functions for data cache access
/// Sends write request to lower level memory (write or writeback)
void send_write_request(mem_fetch *mf, cache_event request, unsigned time, std::list<cache_event> &events);
- /// Sends read request, and possible write-back request, to lower level memory for a write miss with write-allocate
- bool send_write_allocate(mem_fetch *mf, new_addr_type addr, new_addr_type block_addr, unsigned cache_index, unsigned time, std::list<cache_event> &events);
+
+
+ // Member Function pointers - Set by configuration options to the functions below each grouping
+ /******* Write-hit configs *******/
+ enum cache_request_status (data_cache::*m_wr_hit)(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events);
/// Marks block as MODIFIED and updates block LRU
- void write_back_hit(new_addr_type block_addr, unsigned time, unsigned cache_index);
+ enum cache_request_status wr_hit_wb(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events); // write-back
+ enum cache_request_status wr_hit_wt(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events); // write-through
/// Marks block as INVALID and sends write request to lower level memory
- bool do_write_evict(mem_fetch *mf, unsigned time, unsigned cache_index, std::list<cache_event> &events);
+ enum cache_request_status wr_hit_we(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events); // write-evict
+ enum cache_request_status wr_hit_global_we_local_wb(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events); // global write-evict, local write-back
+
+
+ /******* Write-miss configs *******/
+ enum cache_request_status (data_cache::*m_wr_miss)(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events);
+ /// 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); // write-allocate
+ enum cache_request_status wr_miss_no_wa(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events); // no write-allocate
+
+ // Currently no separate functions for reads
+ /******* Read-hit configs *******/
+ enum cache_request_status (data_cache::*m_rd_hit)(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events);
+ enum cache_request_status rd_hit_base(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events);
+
+ /******* Read-miss configs *******/
+ enum cache_request_status (data_cache::*m_rd_miss)(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events);
+ enum cache_request_status rd_miss_base(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events);
+
};
/// This is meant to model the first level data cache in Fermi.
@@ -468,6 +515,7 @@ public:
: data_cache(name,config,core_id,type_id,memport,mfcreator,status){}
virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events );
+
};
/// Models second level shared cache with global write-back and write-allocate policies