summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTayler Hetherington <[email protected]>2012-09-16 13:38:57 -0800
committerAndrew Boktor <[email protected]>2014-08-14 13:49:20 -0700
commit9ceb6f2016a16aa9c877956fc2e8bc43dc697322 (patch)
tree52f22dd215702ad439e73800388a978b8125af8f
parent960a55b075be901ca14d1878f886bbea73456663 (diff)
Modified the cache hierarchy, reorganized code to eliminate code replication, implemented write allocate / write back policies in L2 cache, added configurable parameters in gpgpusim.config ("W" = Write Allocate, "N" = No write allocate -> "P" = Private, "S" = shared), modified the cache configuration lines to always be separated by ":" instead of ":" and ",", and modified L1 and L2 data cache to be "Write Back" caches instead of "Read Only".
Still need to implement Ahmed's sectored cache implementation. [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 14081]
-rw-r--r--configs/GTX480/gpgpusim.config10
-rw-r--r--configs/QuadroFX5800/gpgpusim.config8
-rw-r--r--configs/TeslaC2050/gpgpusim.config10
-rw-r--r--src/abstract_hardware_model.h1
-rw-r--r--src/gpgpu-sim/gpu-cache.cc4
-rw-r--r--src/gpgpu-sim/gpu-cache.h306
-rw-r--r--src/gpgpu-sim/l2cache.cc11
-rw-r--r--src/gpgpu-sim/mem_fetch.cc1
-rw-r--r--src/gpgpu-sim/mem_fetch.h4
-rw-r--r--src/gpgpu-sim/shader.cc2
-rw-r--r--src/gpgpu-sim/shader.h3
11 files changed, 248 insertions, 112 deletions
diff --git a/configs/GTX480/gpgpusim.config b/configs/GTX480/gpgpusim.config
index a3450e1..5cda42a 100644
--- a/configs/GTX480/gpgpusim.config
+++ b/configs/GTX480/gpgpusim.config
@@ -39,7 +39,7 @@
# In Fermi, the cache and shared memory can be configured to 16kb:48kb(default) or 48kb:16kb
# <nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>
--gpgpu_cache:dl1 32:128:4:L:R:m,A:32:8,8
+-gpgpu_cache:dl1 32:128:4:L:B:m:A:P:N:32:8,8
-gpgpu_shmem_size 49152
# The alternative configuration for fermi in case cudaFuncCachePreferL1 is selected
@@ -47,12 +47,12 @@
#-gpgpu_shmem_size 16384
# 64 sets, each 256 bytes 8-way for each memory partition. This gives 786KB L2 cache
--gpgpu_cache:dl2 64:256:8:L:R:m,A:32:4,4
+-gpgpu_cache:dl2 64:256:8:L:B:m:A:S:W:32:4:4
-gpgpu_cache:dl2_texture_only 0
--gpgpu_cache:il1 4:128:4:L:R:f,A:2:32,4
--gpgpu_tex_cache:l1 4:128:24:L:R:m,F:128:4,128:2
--gpgpu_const_cache:l1 64:64:2:L:R:f,A:2:32,4
+-gpgpu_cache:il1 4:128:4:L:R:f:A:P:N:2:32:4
+-gpgpu_tex_cache:l1 4:128:24:L:R:m:F:P:N:128:4:128:2
+-gpgpu_const_cache:l1 64:64:2:L:R:f:A:P:N:2:32:4
-gpgpu_num_reg_banks 16
diff --git a/configs/QuadroFX5800/gpgpusim.config b/configs/QuadroFX5800/gpgpusim.config
index fbe21d7..20cb968 100644
--- a/configs/QuadroFX5800/gpgpusim.config
+++ b/configs/QuadroFX5800/gpgpusim.config
@@ -31,10 +31,10 @@
-ptx_opcode_initiation_dp 8,8,8,8,130
# memory stage behaviour
--gpgpu_cache:il1 4:256:4:L:R:f,A:2:32,4
--gpgpu_tex_cache:l1 8:128:5:L:R:m,F:128:4,128:2
--gpgpu_const_cache:l1 64:64:2:L:R:f,A:2:32,4
--gpgpu_cache:dl2 16:256:8:L:R:m,A:16:4,4
+-gpgpu_cache:il1 4:256:4:L:R:f:A:P:N:2:32,4
+-gpgpu_tex_cache:l1 8:128:5:L:R:m:F:P:N:128:4,128:2
+-gpgpu_const_cache:l1 64:64:2:L:R:f:A:P:N:2:32,4
+-gpgpu_cache:dl2 16:256:8:L:B:m:A:S:W:16:4,4
-gpgpu_cache:dl2_texture_only 1
-gpgpu_shmem_warp_parts 2
diff --git a/configs/TeslaC2050/gpgpusim.config b/configs/TeslaC2050/gpgpusim.config
index 77a81a2..2407ea9 100644
--- a/configs/TeslaC2050/gpgpusim.config
+++ b/configs/TeslaC2050/gpgpusim.config
@@ -39,7 +39,7 @@
# In Fermi, the cache and shared memory can be configured to 16kb:48kb(default) or 48kb:16kb
# <nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>
--gpgpu_cache:dl1 32:128:4:L:R:m,A:32:8,8
+-gpgpu_cache:dl1 32:128:4:L:B:m:A:P:N:32:8,8
-gpgpu_shmem_size 49152
# The alternative configuration for fermi in case cudaFuncCachePreferL1 is selected
@@ -47,12 +47,12 @@
#-gpgpu_shmem_size 16384
# 64 sets, each 256 bytes 8-way for each memory partition. This gives 786KB L2 cache
--gpgpu_cache:dl2 64:256:8:L:R:m,A:32:4,4
+-gpgpu_cache:dl2 64:256:8:L:B:m:A:S:W:32:4:4
-gpgpu_cache:dl2_texture_only 0
--gpgpu_cache:il1 4:128:4:L:R:f,A:2:32,4
--gpgpu_tex_cache:l1 4:128:24:L:R:m,F:128:4,128:2
--gpgpu_const_cache:l1 64:64:2:L:R:f,A:2:32,4
+-gpgpu_cache:il1 4:128:4:L:R:f:A:P:N:2:32:4
+-gpgpu_tex_cache:l1 4:128:24:L:R:m:F:P:N:128:4:128:2
+-gpgpu_const_cache:l1 64:64:2:L:R:f:A:P:N:2:32:4
-gpgpu_num_reg_banks 16
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 3bde119..183123b 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -495,6 +495,7 @@ enum mem_access_type {
L1_WRBK_ACC,
L2_WRBK_ACC,
INST_ACC_R,
+ L2_WR_ALLOC_R,
NUM_MEM_ACCESS_TYPE
};
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index 043c583..ace2686 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -37,7 +37,7 @@ tag_array::~tag_array()
tag_array::tag_array( const cache_config &config, int core_id, int type_id )
: m_config(config), m_access(0), m_miss(0), m_pending_hit(0)
{
- assert( m_config.m_write_policy == READ_ONLY );
+ //assert( m_config.m_write_policy == READ_ONLY ); Old assert
m_lines = new cache_block_t[ config.get_num_lines()];
// initialize snapshot counters for visualizer
@@ -49,7 +49,7 @@ tag_array::tag_array( const cache_config &config, int core_id, int type_id )
}
enum cache_request_status tag_array::probe( new_addr_type addr, unsigned &idx ) const {
- assert( m_config.m_write_policy == READ_ONLY );
+ //assert( m_config.m_write_policy == READ_ONLY );
unsigned set_index = m_config.set_index(addr);
new_addr_type tag = m_config.tag(addr);
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 3f67ffe..5200850 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -105,6 +105,17 @@ enum allocation_policy_t {
ON_FILL
};
+
+enum write_allocate_policy_t {
+ NO_WRITE_ALLOCATE,
+ WRITE_ALLOCATE
+};
+
+enum cache_scope_t {
+ PRIVATE,
+ SHARED
+};
+
enum mshr_config_t {
TEX_FIFO,
ASSOC // normal cache
@@ -121,10 +132,13 @@ public:
void init()
{
assert( m_config_string );
- char rp, wp, ap, mshr_type;
- int ntok = sscanf(m_config_string,"%u:%u:%u:%c:%c:%c,%c:%u:%u,%u:%u",
+ char rp, wp, ap, mshr_type, scope, wap;
+
+ int ntok = sscanf(m_config_string,"%u:%u:%u:%c:%c:%c:%c:%c:%c:%u:%u:%u:%u",
&m_nset, &m_line_sz, &m_assoc, &rp, &wp, &ap,
- &mshr_type,&m_mshr_entries,&m_mshr_max_merge,&m_miss_queue_size,&m_result_fifo_entries);
+ &mshr_type, &scope, &wap, &m_mshr_entries,&m_mshr_max_merge,
+ &m_miss_queue_size,&m_result_fifo_entries);
+
if ( ntok < 10 ) {
if ( !strcmp(m_config_string,"none") ) {
m_disabled = true;
@@ -149,13 +163,24 @@ public:
default: exit_parse_error();
}
switch (mshr_type) {
- case 'F': m_mshr_type = TEX_FIFO; assert(ntok==11); break;
+ case 'F': m_mshr_type = TEX_FIFO; assert(ntok==13); break;
case 'A': m_mshr_type = ASSOC; break;
default: exit_parse_error();
}
m_line_sz_log2 = LOGB2(m_line_sz);
m_nset_log2 = LOGB2(m_nset);
m_valid = true;
+
+ switch(scope){
+ case 'P': m_cache_scope = PRIVATE; break;
+ case 'S': m_cache_scope = SHARED; break;
+ default: exit_parse_error();
+ }
+ switch(wap){
+ case 'W': m_write_aclloc_policy = WRITE_ALLOCATE; break;
+ case 'N': m_write_aclloc_policy = NO_WRITE_ALLOCATE; break;
+ default: exit_parse_error();
+ }
}
bool disabled() const { return m_disabled;}
unsigned get_line_sz() const
@@ -211,6 +236,9 @@ private:
enum allocation_policy_t m_alloc_policy; // 'm' = allocate on miss, 'f' = allocate on fill
enum mshr_config_t m_mshr_type;
+ cache_scope_t m_cache_scope; // 'P' = PRIVATE, 'S' = SHARED
+ write_allocate_policy_t m_write_aclloc_policy; // 'W' = Write allocate, 'N' = No write allocate
+
union {
unsigned m_mshr_entries;
unsigned m_fragment_fifo_entries;
@@ -226,6 +254,7 @@ private:
unsigned m_result_fifo_entries;
friend class tag_array;
+ friend class baseline_cache;
friend class read_only_cache;
friend class tex_cache;
friend class data_cache;
@@ -385,6 +414,9 @@ private:
std::list<new_addr_type> m_current_response;
};
+
+/***************************************************************** Caches *****************************************************************/
+
class cache_t {
public:
virtual ~cache_t() {}
@@ -394,9 +426,9 @@ public:
bool was_write_sent( const std::list<cache_event> &events );
bool was_read_sent( const std::list<cache_event> &events );
-class read_only_cache : public cache_t {
+class baseline_cache : public cache_t {
public:
- read_only_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport,
+ baseline_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport,
enum mem_fetch_status status )
: m_config(config), m_tag_array(config,core_id,type_id), m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge)
{
@@ -406,41 +438,6 @@ public:
m_miss_queue_status = status;
}
- // access cache: returns RESERVATION_FAIL if request could not be accepted (for any reason)
- virtual enum cache_request_status 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 ) {
- bool mshr_hit = m_mshrs.probe(block_addr);
- bool mshr_avail = !m_mshrs.full(block_addr);
- if ( mshr_hit && mshr_avail ) {
- m_tag_array.access(addr,time,cache_index);
- m_mshrs.add(block_addr,mf);
- return MISS;
- } else if ( !mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size) ) {
- m_tag_array.access(addr,time,cache_index);
- 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_miss_queue.push_back(mf);
- mf->set_status(m_miss_queue_status,time);
- events.push_back(READ_REQUEST_SENT);
- return MISS;
- }
- }
- return RESERVATION_FAIL;
- }
-
void cycle()
{
// send next request to lower level of memory
@@ -540,113 +537,236 @@ public:
typedef std::map<mem_fetch*,extra_mf_fields> extra_mf_fields_lookup;
extra_mf_fields_lookup m_extra_mf_fields;
+
+
+ bool miss_queue_full(unsigned num_miss){
+ // Checks whether this request can be handled on this cycle. num_miss equals max # of misses to be handled on this cycle
+ return ( (m_miss_queue.size()+num_miss) >= m_config.m_miss_queue_size );
+ }
+
+ void read_request(new_addr_type addr, new_addr_type block_addr, unsigned cache_index, mem_fetch *mf,
+ unsigned time, bool &do_miss, std::list<cache_event> &events, bool read_only){
+ // Read miss handler without writeback
+ bool wb=false;
+ cache_block_t e;
+ read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, e, events, read_only);
+ }
+
+ void 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){
+ // Read miss handler. Check MSHR hit or MSHR available
+
+ if(m_config.set_index(addr) != m_config.set_index(block_addr))
+ abort();
+ if(m_config.tag(addr) != m_config.tag(block_addr))
+ abort();
+
+ bool mshr_hit = m_mshrs.probe(block_addr);
+ bool mshr_avail = !m_mshrs.full(block_addr);
+ if ( mshr_hit && mshr_avail ) {
+ if(read_only)
+ m_tag_array.access(block_addr,time,cache_index);
+ else
+ m_tag_array.access(block_addr,time,cache_index,wb,evicted);
+
+ m_mshrs.add(block_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);
+ else
+ m_tag_array.access(block_addr,time,cache_index,wb,evicted);
+
+ 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_miss_queue.push_back(mf);
+ mf->set_status(m_miss_queue_status,time);
+ events.push_back(READ_REQUEST_SENT);
+ do_miss = true;
+ }
+ }
+};
+
+
+
+class read_only_cache : public baseline_cache {
+public:
+ read_only_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, enum mem_fetch_status status )
+ : baseline_cache(name,config,core_id,type_id,memport,status){}
+
+ // access cache: returns RESERVATION_FAIL if request could not be accepted (for any reason)
+ virtual enum cache_request_status 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)){
+ bool do_miss=false;
+ read_request(addr, block_addr, cache_index, mf, time, do_miss, events, true);
+ if(do_miss)
+ return MISS;
+ }
+ }
+ 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 (the policy used in fermi according to the CUDA manual)
-class data_cache : public read_only_cache {
+class data_cache : public baseline_cache {
public:
- data_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport,
+ data_cache( const char *name, const cache_config &config,
+ int core_id, int type_id, mem_fetch_interface *memport,
mem_fetch_allocator *mfcreator, enum mem_fetch_status status )
- : read_only_cache(name,config,core_id,type_id,memport,status)
+ : baseline_cache(name,config,core_id,type_id,memport,status)
{
m_memfetch_creator=mfcreator;
}
- virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events )
- {
+
+
+ virtual enum cache_request_status 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();
- 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 ( status == HIT ) {
- if ( evict ) {
- if ( m_miss_queue.size() >= m_config.m_miss_queue_size )
- return RESERVATION_FAIL; // cannot handle request this cycle
+
+ // If write through policy or private cache with global write hit
+ if(wr && (m_config.m_write_policy == WRITE_THROUGH ||
+ ( (m_config.m_cache_scope == PRIVATE) && (type == GLOBAL_ACC_W) ))){
+ // Write through
+ if(miss_queue_full(0))
+ return RESERVATION_FAIL; // cannot handle request this cycle
// generate a write through
cache_block_t &block = m_tag_array.get_block(cache_index);
- // assert( block.m_status != MODIFIED ); // fails if block was allocated by a ld.local and now accessed by st.global
- m_miss_queue.push_back(mf);
- mf->set_status(m_miss_queue_status,time);
- events.push_back(WRITE_REQUEST_SENT);
+ write_request(mf, WRITE_REQUEST_SENT, time, events);
- // invalidate block
+ // invalidate block
block.m_status = INVALID;
- } else {
- m_tag_array.access(block_addr,time,cache_index); // update LRU state
+
+ }else{ // Write back cache or global read hit
+ m_tag_array.access(block_addr,time,cache_index); // update LRU state
if ( wr ) {
- assert( type == LOCAL_ACC_W || /*l2 only*/ type == L1_WRBK_ACC );
+ assert( type == LOCAL_ACC_W || type == L1_WRBK_ACC || m_config.m_cache_scope == SHARED);
// treated as write back...
cache_block_t &block = m_tag_array.get_block(cache_index);
block.m_status = MODIFIED;
} else if ( isatomic ) {
- assert( type == GLOBAL_ACC_R );
+ 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
+ block.m_status = MODIFIED; // mark line as dirty
}
- }
+ }
return HIT;
} else if ( status != RESERVATION_FAIL ) {
if ( wr ) {
- if ( m_miss_queue.size() >= m_config.m_miss_queue_size )
- return RESERVATION_FAIL; // cannot handle request this cycle
+ if(m_config.m_write_aclloc_policy == NO_WRITE_ALLOCATE){
+ // No write allocate, maximum 1 requests
+ if(miss_queue_full(0))
+ return RESERVATION_FAIL; // cannot handle request this cycle
+ }else{
+ // 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;
+ }
+
+ // on miss, generate write through (no write buffering -- too many threads for that)
+ write_request(mf, WRITE_REQUEST_SENT, time, events);
+
+ // If no write allocate, simply return miss
+ if(m_config.m_write_aclloc_policy == NO_WRITE_ALLOCATE)
+ return MISS;
+
+ // Write allocate - Generate new read miss
+ 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() );
+
+ 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());
+
+ bool do_miss = false;
+ bool wb = false;
+ cache_block_t evicted;
+
+ // Send read request resulting from write miss
+ read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb, evicted, events, false);
+
+ if( wb ) { // If evicted block is modified
+ mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,L2_WRBK_ACC,m_config.get_line_sz(),true);
+ m_miss_queue.push_back(wb);
+ wb->set_status(m_miss_queue_status,time);
+ }
+ if( do_miss )
+ return MISS;
+ return RESERVATION_FAIL;
- // on miss, generate write through (no write buffering -- too many threads for that)
- m_miss_queue.push_back(mf);
- mf->set_status(m_miss_queue_status,time);
- events.push_back(WRITE_REQUEST_SENT);
- return MISS;
} else {
- if ( (m_miss_queue.size()+1) >= m_config.m_miss_queue_size )
- return RESERVATION_FAIL; // cannot handle request this cycle (might need to generate two requests)
+ 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;
+ read_request(addr, block_addr, cache_index, mf, time, do_miss, wb, evicted, events, false);
- bool mshr_hit = m_mshrs.probe(block_addr);
- bool mshr_avail = !m_mshrs.full(block_addr);
- if ( mshr_hit && mshr_avail ) {
- m_tag_array.access(addr,time,cache_index,wb,evicted);
- m_mshrs.add(block_addr,mf);
- do_miss = true;
- } else if ( !mshr_hit && mshr_avail && (m_miss_queue.size() < m_config.m_miss_queue_size) ) {
- m_tag_array.access(addr,time,cache_index,wb,evicted);
- 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_miss_queue.push_back(mf);
- mf->set_status(m_miss_queue_status,time);
- events.push_back(READ_REQUEST_SENT);
- do_miss = true;
- }
- if( wb ) {
- assert(do_miss);
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,L1_WRBK_ACC,m_config.get_line_sz(),true);
- events.push_back(WRITE_BACK_REQUEST_SENT);
- m_miss_queue.push_back(wb);
- wb->set_status(m_miss_queue_status,time);
+ if(wb){
+ mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr, L1_WRBK_ACC,m_config.get_line_sz(),true);
+ write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
}
if( do_miss )
return MISS;
}
}
-
return RESERVATION_FAIL;
}
+
+
private:
mem_fetch_allocator *m_memfetch_creator;
+
+ // Private functions for data cache access
+
+ void write_request(mem_fetch *mf, cache_event request, unsigned time, std::list<cache_event> &events){
+ // Send write request to lower level memory (write or writeback)
+ events.push_back(request);
+ m_miss_queue.push_back(mf);
+ mf->set_status(m_miss_queue_status,time);
+ }
};
+/********************************************************************************************************************************************************/
+
// See the following paper to understand this cache model:
//
// Igehy, et al., Prefetching in a Texture Cache Architecture,
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index a252c84..a580052 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -105,9 +105,14 @@ void memory_partition_unit::cache_cycle( unsigned cycle )
if( !m_config->m_L2_config.disabled()) {
if ( m_L2cache->access_ready() && !m_L2_icnt_queue->full() ) {
mem_fetch *mf = m_L2cache->next_access();
- 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);
+ if(mf->get_access_type() != L2_WR_ALLOC_R){ // Don't pass write allocate read request back to upper level cache
+ 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);
+ }else{
+ m_request_tracker.erase(mf);
+ delete mf;
+ }
}
}
diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc
index a085cd9..97721c0 100644
--- a/src/gpgpu-sim/mem_fetch.cc
+++ b/src/gpgpu-sim/mem_fetch.cc
@@ -59,6 +59,7 @@ mem_fetch::mem_fetch( const mem_access_t &access,
m_timestamp2 = 0;
m_status = MEM_FETCH_INITIALIZED;
m_status_change = gpu_sim_cycle + gpu_tot_sim_cycle;
+ m_mem_config = config;
}
mem_fetch::~mem_fetch()
diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h
index a4e8499..501d52a 100644
--- a/src/gpgpu-sim/mem_fetch.h
+++ b/src/gpgpu-sim/mem_fetch.h
@@ -99,10 +99,12 @@ public:
enum mem_access_type get_access_type() const { return m_access.get_type(); }
const active_mask_t& get_access_warp_mask() const { return m_access.get_warp_mask(); }
+ mem_access_byte_mask_t get_access_byte_mask() const { return m_access.get_byte_mask(); }
address_type get_pc() const { return m_inst.empty()?-1:m_inst.pc; }
const warp_inst_t &get_inst() { return m_inst; }
enum mem_fetch_status get_status() const { return m_status; }
+ const memory_config *get_mem_config(){return m_mem_config;}
private:
// request source information
unsigned m_request_uid;
@@ -131,6 +133,8 @@ private:
warp_inst_t m_inst;
static unsigned sm_next_mf_request_uid;
+
+ const class memory_config *m_mem_config;
};
#endif
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index b3e5fc5..7b65add 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -2395,6 +2395,8 @@ void simt_core_cluster::icnt_inject_request_packet(class mem_fetch *mf)
case LOCAL_ACC_W: m_stats->gpgpu_n_mem_write_local++; break;
case INST_ACC_R: m_stats->gpgpu_n_mem_read_inst++; break;
case L1_WRBK_ACC: m_stats->gpgpu_n_mem_write_global++; break;
+ case L2_WRBK_ACC: m_stats->gpgpu_n_mem_l2_writeback++; break;
+ case L2_WR_ALLOC_R: m_stats->gpgpu_n_mem_l2_write_allocate++; break;
default: assert(0);
}
unsigned destination = mf->get_tlx_addr().chip;
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 86a1a86..078633d 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -1109,6 +1109,9 @@ struct shader_core_stats_pod {
int gpgpu_n_mem_write_global;
int gpgpu_n_mem_read_inst;
+ int gpgpu_n_mem_l2_writeback;
+ int gpgpu_n_mem_l2_write_allocate;
+
unsigned made_write_mfs;
unsigned made_read_mfs;
};