summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES3
-rw-r--r--src/gpgpu-sim/gpu-cache.cc269
-rw-r--r--src/gpgpu-sim/gpu-cache.h188
-rw-r--r--src/gpgpu-sim/shader.cc98
-rw-r--r--src/gpgpu-sim/shader.h23
5 files changed, 435 insertions, 146 deletions
diff --git a/CHANGES b/CHANGES
index 70a263d..d74f655 100644
--- a/CHANGES
+++ b/CHANGES
@@ -26,6 +26,9 @@ Version 3.2.1+edits (development branch) versus 3.2.1
- Changes to the makefiles s.t. all intermediate files get output to the build
directory, and nothing is written to the same directory as the source code
- Implemented the WARPSZ query in CUDA.
+- Implemented a Static Warp Limiting Scheduler similar described in Rogers et. al.
+ (MICRO 2012).
+- Some whitespace cleanup.
- Bug Fixes:
- Fixed the flit count sent to GPUWattch for atomic operations.
- Fix for Bug 51 - Updated the function declaration of
diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc
index f6f8ac8..4c5c5c9 100644
--- a/src/gpgpu-sim/gpu-cache.cc
+++ b/src/gpgpu-sim/gpu-cache.cc
@@ -204,6 +204,10 @@ enum cache_request_status tag_array::access( new_addr_type addr, unsigned time,
m_res_fail++;
shader_cache_access_log(m_core_id, m_type_id, 1); // log cache misses
break;
+ default:
+ fprintf( stderr, "tag_array::access - Error: Unknown"
+ "cache_request_status %d\n", status );
+ abort();
}
return status;
}
@@ -660,22 +664,30 @@ enum cache_request_status data_cache::wr_hit_global_we_local_wb(new_addr_type ad
/****** 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, enum cache_request_status status) {
-
+/// 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,
+ enum cache_request_status status )
+{
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))))
+ 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;
+ // return RESERVATION_FAIL;
const mem_access_t *ma = new mem_access_t( L2_WR_ALLOC_R,
mf->get_addr(),
@@ -697,11 +709,15 @@ enum cache_request_status data_cache::wr_miss_wa(new_addr_type addr, unsigned ca
cache_block_t evicted;
// Send read request resulting from write miss
- send_read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb, evicted, events, false, true);
+ send_read_request(addr, block_addr, cache_index, n_mf, time, do_miss, wb,
+ evicted, events, false, true);
if( do_miss ){
- if( wb && (m_config.m_write_policy != WRITE_THROUGH) ) { // If evicted block is modified and not a write-through (already modified lower level)
- mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,L2_WRBK_ACC,m_config.get_line_sz(),true);
+ // 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,
+ L2_WRBK_ACC,m_config.get_line_sz(),true);
m_miss_queue.push_back(wb);
wb->set_status(m_miss_queue_status,time);
}
@@ -712,55 +728,93 @@ enum cache_request_status data_cache::wr_miss_wa(new_addr_type addr, unsigned ca
}
/// 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, enum cache_request_status status ){
- if(miss_queue_full(0))
- return RESERVATION_FAIL; // cannot handle request this cycle
+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,
+ enum cache_request_status status )
+{
+ 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);
+ // 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 MISS;
}
/****** 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, enum cache_request_status status ){
- 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);
+/// 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,
+ enum cache_request_status status )
+{
+ new_addr_type block_addr = m_config.block_addr(addr);
+ m_tag_array->access(block_addr,time,cache_index);
+ // 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
- }
- return HIT;
+ }
+ 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, enum cache_request_status status ){
+/// 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,
+ enum cache_request_status status ){
if(miss_queue_full(1))
- return RESERVATION_FAIL; // cannot handle request this cycle (might need to generate two requests)
+ // cannot handle request this cycle
+ // (might need to generate two requests)
+ return RESERVATION_FAIL;
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);
+ send_read_request( addr,
+ block_addr,
+ cache_index,
+ mf, time, do_miss, wb, evicted, events, false, false);
if( do_miss ){
- if(wb && (m_config.m_write_policy != WRITE_THROUGH) ){ // If evicted block is modified and not a write-through (already modified lower level)
- 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 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,
+ L1_WRBK_ACC,m_config.get_line_sz(),true);
+ send_write_request(wb, WRITE_BACK_REQUEST_SENT, time, events);
+ }
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 ) {
+/// 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());
@@ -776,11 +830,11 @@ enum cache_request_status read_only_cache::access( new_addr_type addr, mem_fetch
bool do_miss=false;
send_read_request(addr, block_addr, cache_index, mf, time, do_miss, events, true, false);
if(do_miss)
- cache_status = MISS;
+ cache_status = MISS;
else
- cache_status = RESERVATION_FAIL;
+ cache_status = RESERVATION_FAIL;
}else{
- cache_status = RESERVATION_FAIL;
+ cache_status = RESERVATION_FAIL;
}
}
@@ -788,65 +842,95 @@ enum cache_request_status read_only_cache::access( new_addr_type addr, mem_fetch
return cache_status;
}
-/// 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 (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();
- 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 cache_status = RESERVATION_FAIL;
-
- // Each function pointer ( m_[rd/wr]_[hit/miss] ) is set in the data_cache constructor to reflect the corresponding cache configuration options.
- // Function pointers were used to avoid many long conditional branches resulting from many cache configuration options.
- if(wr){ // Write
- if(status == HIT){
- cache_status = (this->*m_wr_hit)(addr, cache_index, mf, time, events, status);
- }else if ( status != RESERVATION_FAIL ) {
- cache_status = (this->*m_wr_miss)(addr, cache_index, mf, time, events, status);
+//! A general function that takes the result of a tag_array probe
+// and performs the correspding functions based on the cache configuration
+// The access fucntion calls this function
+enum cache_request_status
+data_cache::process_tag_probe( bool wr,
+ enum cache_request_status probe_status,
+ new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch* mf,
+ unsigned time,
+ std::list<cache_event>& events )
+{
+ // Each function pointer ( m_[rd/wr]_[hit/miss] ) is set in the
+ // data_cache constructor to reflect the corresponding cache configuration
+ // options. Function pointers were used to avoid many long conditional
+ // branches resulting from many cache configuration options.
+ cache_request_status access_status = probe_status;
+ if(wr){ // Write
+ if(probe_status == HIT){
+ access_status = (this->*m_wr_hit)( addr,
+ cache_index,
+ mf, time, events, probe_status );
+ }else if ( probe_status != RESERVATION_FAIL ) {
+ access_status = (this->*m_wr_miss)( addr,
+ cache_index,
+ mf, time, events, probe_status );
}
}else{ // Read
- if(status == HIT){
- cache_status = (this->*m_rd_hit)(addr, cache_index, mf, time, events, status);
- }else if ( status != RESERVATION_FAIL ) {
- cache_status = (this->*m_rd_miss)(addr, cache_index, mf, time, events, status);
+ if(probe_status == HIT){
+ access_status = (this->*m_rd_hit)( addr,
+ cache_index,
+ mf, time, events, probe_status );
+ }else if ( probe_status != RESERVATION_FAIL ) {
+ access_status = (this->*m_rd_miss)( addr,
+ cache_index,
+ mf, time, events, probe_status );
}
}
- m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
- return cache_status;
+ return access_status;
}
-/// 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 ){
+// Both the L1 and L2 currently use the same access function.
+// Differentiation between the two caches is done through configuration
+// of caching policies.
+// Both the L1 and L2 override this function to provide a means of
+// performing actions specific to each cache when such actions are implemnted.
+enum cache_request_status
+data_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();
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 cache_status = RESERVATION_FAIL;
+ enum cache_request_status probe_status
+ = m_tag_array->probe( block_addr, cache_index );
+ 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));
+ return access_status;
+}
- // Each function pointer ( m_[rd/wr]_[hit/miss] ) is set in the data_cache constructor to reflect the corresponding cache configuration options.
- // Function pointers were used to avoid many long conditional branches resulting from many cache configuration options.
- if(wr){ // Write
- if(status == HIT){
- cache_status = (this->*m_wr_hit)(addr, cache_index, mf, time, events, status);
- }else if ( status != RESERVATION_FAIL ) {
- cache_status = (this->*m_wr_miss)(addr, cache_index, mf, time, events, status);
- }
- }else{ // Read
- if(status == HIT){
- cache_status = (this->*m_rd_hit)(addr, cache_index, mf, time, events, status);
- }else if ( status != RESERVATION_FAIL ) {
- cache_status = (this->*m_rd_miss)(addr, cache_index, mf, time, events, status);
- }
- }
- m_stats.inc_stats(mf->get_access_type(), m_stats.select_stats_status(status, cache_status));
- return cache_status;
+/// 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 (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 )
+{
+ return data_cache::access( addr, mf, time, events );
+}
+
+// The l2 cache access function calls the base data_cache access
+// implementation. When the L2 needs to diverge from L1, L2 specific
+// changes should be made here.
+enum cache_request_status
+l2_cache::access( new_addr_type addr,
+ mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events )
+{
+ return data_cache::access( addr, mf, time, events );
}
/// Access function for tex_cache
@@ -854,7 +938,9 @@ enum cache_request_status l2_cache::access( new_addr_type addr, mem_fetch *mf, u
/// otherwise returns HIT_RESERVED or MISS; NOTE: *never* returns HIT
/// since unlike a normal CPU cache, a "HIT" in texture cache does not
/// mean the data is ready (still need to get through fragment fifo)
-enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ) {
+enum cache_request_status tex_cache::access( new_addr_type addr, mem_fetch *mf,
+ unsigned time, std::list<cache_event> &events )
+{
if ( m_fragment_fifo.full() || m_request_fifo.full() || m_rob.full() )
return RESERVATION_FAIL;
@@ -915,7 +1001,8 @@ void tex_cache::cycle(){
} else {
// hit:
assert( m_cache[e.m_cache_index].m_valid );
- assert( m_cache[e.m_cache_index].m_block_addr = m_config.block_addr(e.m_request->get_addr()) );
+ assert( m_cache[e.m_cache_index].m_block_addr
+ == m_config.block_addr(e.m_request->get_addr()) );
m_result_fifo.push( e.m_request );
m_fragment_fifo.pop();
}
@@ -942,15 +1029,19 @@ void tex_cache::fill( mem_fetch *mf, unsigned time )
void tex_cache::display_state( FILE *fp ) const
{
fprintf(fp,"%s (texture cache) state:\n", m_name.c_str() );
- fprintf(fp,"fragment fifo entries = %u / %u\n", m_fragment_fifo.size(), m_fragment_fifo.capacity() );
- fprintf(fp,"reorder buffer entries = %u / %u\n", m_rob.size(), m_rob.capacity() );
- fprintf(fp,"request fifo entries = %u / %u\n", m_request_fifo.size(), m_request_fifo.capacity() );
+ fprintf(fp,"fragment fifo entries = %u / %u\n",
+ m_fragment_fifo.size(), m_fragment_fifo.capacity() );
+ fprintf(fp,"reorder buffer entries = %u / %u\n",
+ m_rob.size(), m_rob.capacity() );
+ fprintf(fp,"request fifo entries = %u / %u\n",
+ m_request_fifo.size(), m_request_fifo.capacity() );
if ( !m_rob.empty() )
fprintf(fp,"reorder buffer contents:\n");
for ( int n=m_rob.size()-1; n>=0; n-- ) {
unsigned index = (m_rob.next_pop_index() + n)%m_rob.capacity();
const rob_entry &r = m_rob.peek(index);
- fprintf(fp, "tex rob[%3d] : %s ", index, (r.m_ready?"ready ":"pending") );
+ fprintf(fp, "tex rob[%3d] : %s ",
+ index, (r.m_ready?"ready ":"pending") );
if ( r.m_ready )
fprintf(fp,"@%6u", r.m_time );
else
diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h
index 011b1f5..594125e 100644
--- a/src/gpgpu-sim/gpu-cache.h
+++ b/src/gpgpu-sim/gpu-cache.h
@@ -352,7 +352,6 @@ protected:
int m_type_id; // what kind of cache is this (normal, texture, constant)
};
-
class mshr_table {
public:
mshr_table( unsigned num_entries, unsigned max_merged )
@@ -634,7 +633,7 @@ public:
virtual ~data_cache() {}
- void init( mem_fetch_allocator *mfcreator )
+ virtual void init( mem_fetch_allocator *mfcreator )
{
m_memfetch_creator=mfcreator;
@@ -646,26 +645,39 @@ public:
// 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
+ // READ_ONLY is now a separate cache class, config is deprecated
+ case READ_ONLY:
+ assert(0 && "Error: Writable Data_cache set as READ_ONLY\n");
+ break;
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
+ 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
+ default:
+ assert(0 && "Error: Must set valid cache write miss policy\n");
+ break; // Need to set a write miss function
}
}
+ virtual enum cache_request_status access( new_addr_type addr,
+ mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events );
protected:
data_cache( const char *name,
cache_config &config,
- int core_id,
+ int core_id,
int type_id,
mem_fetch_interface *memport,
mem_fetch_allocator *mfcreator,
@@ -675,85 +687,185 @@ protected:
{
init( mfcreator );
}
+ //! A general function that takes the result of a tag_array probe
+ // and performs the correspding functions based on the cache configuration
+ // The access fucntion calls this function
+ enum cache_request_status
+ process_tag_probe( bool wr,
+ enum cache_request_status status,
+ new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch* mf,
+ unsigned time,
+ std::list<cache_event>& events );
protected:
mem_fetch_allocator *m_memfetch_creator;
// 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);
-
+ void send_write_request( mem_fetch *mf,
+ cache_event request,
+ unsigned time,
+ std::list<cache_event> &events);
- // Member Function pointers - Set by configuration options to the functions below each grouping
+ // 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, enum cache_request_status status);
+ 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,
+ enum cache_request_status status );
/// Marks block as MODIFIED and updates block LRU
- enum cache_request_status 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); // 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, enum cache_request_status status); // write-through
+ enum cache_request_status
+ 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 ); // 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,
+ enum cache_request_status status ); // write-through
+
/// Marks block as INVALID and sends write request to lower level memory
- enum cache_request_status 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); // 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, enum cache_request_status status); // global write-evict, local write-back
+ enum cache_request_status
+ 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 ); // 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,
+ enum cache_request_status status );
+ // 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, enum cache_request_status status);
- /// 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
- 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, enum cache_request_status status); // no write-allocate
+ 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,
+ enum cache_request_status status );
+ /// 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
+ 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,
+ enum cache_request_status status ); // 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 status);
- enum cache_request_status rd_hit_base(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status);
+ 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 status );
+ enum cache_request_status
+ rd_hit_base( new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch *mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status );
/******* 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 status);
- enum cache_request_status rd_miss_base(new_addr_type addr, unsigned cache_index, mem_fetch *mf, unsigned time, std::list<cache_event> &events, enum cache_request_status status);
+ 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 status );
+ enum cache_request_status
+ rd_miss_base( new_addr_type addr,
+ unsigned cache_index,
+ mem_fetch*mf,
+ unsigned time,
+ std::list<cache_event> &events,
+ enum cache_request_status status );
};
/// 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
/// (the policy used in fermi according to the CUDA manual)
class l1_cache : public data_cache {
public:
- l1_cache(const char *name, cache_config &config,
- int core_id, int type_id, mem_fetch_interface *memport,
+ l1_cache(const char *name, cache_config &config,
+ int core_id, int type_id, mem_fetch_interface *memport,
mem_fetch_allocator *mfcreator, enum mem_fetch_status status )
- : data_cache(name,config,core_id,type_id,memport,mfcreator,status){}
+ : data_cache(name,config,core_id,type_id,memport,mfcreator,status){}
virtual ~l1_cache(){}
- 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 );
protected:
- l1_cache( const char *name,
+ l1_cache( const char *name,
cache_config &config,
- int core_id,
+ int core_id,
int type_id,
mem_fetch_interface *memport,
mem_fetch_allocator *mfcreator,
enum mem_fetch_status status,
tag_array* new_tag_array )
- : data_cache(name,config,core_id,type_id,memport,mfcreator,status, new_tag_array){}
+ : data_cache( name,
+ config,
+ core_id,type_id,memport,mfcreator,status, new_tag_array ){}
};
-/// Models second level shared cache with global write-back and write-allocate policies
+/// Models second level shared cache with global write-back
+/// and write-allocate policies
class l2_cache : public data_cache {
public:
- l2_cache(const char *name, cache_config &config,
- int core_id, int type_id, mem_fetch_interface *memport,
+ l2_cache(const char *name, cache_config &config,
+ int core_id, int type_id, mem_fetch_interface *memport,
mem_fetch_allocator *mfcreator, enum mem_fetch_status status )
- : data_cache(name,config,core_id,type_id,memport,mfcreator,status){}
+ : data_cache(name,config,core_id,type_id,memport,mfcreator,status){}
virtual ~l2_cache() {}
- 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 );
};
-/********************************************************************************************************************************************************/
+/*****************************************************************************/
// See the following paper to understand this cache model:
//
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 767fb36..5bda78c 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -50,6 +50,7 @@
#define PRIORITIZE_MSHR_OVER_WB 1
#define MAX(a,b) (((a)>(b))?(a):(b))
+#define MIN(a,b) (((a)<(b))?(a):(b))
/////////////////////////////////////////////////////////////////////////////
@@ -131,6 +132,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
CONCRETE_SCHEDULER_TWO_LEVEL_ACTIVE :
sched_config.find("gto") != std::string::npos ?
CONCRETE_SCHEDULER_GTO :
+ sched_config.find("warp_limiting") != std::string::npos ?
+ CONCRETE_SCHEDULER_WARP_LIMITING:
NUM_CONCRETE_SCHEDULERS;
assert ( scheduler != NUM_CONCRETE_SCHEDULERS );
@@ -180,6 +183,21 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu,
)
);
break;
+ case CONCRETE_SCHEDULER_WARP_LIMITING:
+ schedulers.push_back(
+ new swl_scheduler( m_stats,
+ this,
+ m_scoreboard,
+ m_simt_stack,
+ &m_warp,
+ &m_pipeline_reg[ID_OC_SP],
+ &m_pipeline_reg[ID_OC_SFU],
+ &m_pipeline_reg[ID_OC_MEM],
+ i,
+ config->gpgpu_scheduler_string
+ )
+ );
+ break;
default:
abort();
};
@@ -903,7 +921,13 @@ void scheduler_unit::do_on_warp_issued( unsigned warp_id,
bool scheduler_unit::sort_warps_by_oldest_dynamic_id(shd_warp_t* lhs, shd_warp_t* rhs)
{
if (rhs && lhs) {
- return lhs->get_dynamic_warp_id() < rhs->get_dynamic_warp_id();
+ if ( lhs->done_exit() || lhs->waiting() ) {
+ return false;
+ } else if ( rhs->done_exit() || rhs->waiting() ) {
+ return true;
+ } else {
+ return lhs->get_dynamic_warp_id() < rhs->get_dynamic_warp_id();
+ }
} else {
return lhs < rhs;
}
@@ -950,32 +974,32 @@ two_level_active_scheduler::do_on_warp_issued( unsigned warp_id,
void two_level_active_scheduler::order_warps()
{
- //Move waiting warps to m_pending_warps
+ //Move waiting warps to m_pending_warps
unsigned num_demoted = 0;
- for ( std::vector< shd_warp_t* >::iterator iter = m_next_cycle_prioritized_warps.begin();
- iter != m_next_cycle_prioritized_warps.end(); ) {
- bool waiting = (*iter)->waiting();
- for (int i=0; i<4; i++){
- const warp_inst_t* inst = (*iter)->ibuffer_next_inst();
- //Is the instruction waiting on a long operation?
- if ( inst && inst->in[i] > 0 && this->m_scoreboard->islongop((*iter)->get_warp_id(), inst->in[i])){
- waiting = true;
- }
- }
+ for ( std::vector< shd_warp_t* >::iterator iter = m_next_cycle_prioritized_warps.begin();
+ iter != m_next_cycle_prioritized_warps.end(); ) {
+ bool waiting = (*iter)->waiting();
+ for (int i=0; i<4; i++){
+ const warp_inst_t* inst = (*iter)->ibuffer_next_inst();
+ //Is the instruction waiting on a long operation?
+ if ( inst && inst->in[i] > 0 && this->m_scoreboard->islongop((*iter)->get_warp_id(), inst->in[i])){
+ waiting = true;
+ }
+ }
- if( waiting ) {
- m_pending_warps.push_back(*iter);
- iter = m_next_cycle_prioritized_warps.erase(iter);
+ if( waiting ) {
+ m_pending_warps.push_back(*iter);
+ iter = m_next_cycle_prioritized_warps.erase(iter);
SCHED_DPRINTF( "DEMOTED warp_id=%d, dynamic_warp_id=%d\n",
(*iter)->get_warp_id(),
(*iter)->get_dynamic_warp_id() );
++num_demoted;
- } else {
+ } else {
++iter;
}
- }
+ }
- //If there is space in m_next_cycle_prioritized_warps, promote the next m_pending_warps
+ //If there is space in m_next_cycle_prioritized_warps, promote the next m_pending_warps
unsigned num_promoted = 0;
if ( SCHEDULER_PRIORITIZATION_SRR == m_outer_level_prioritization ) {
while ( m_next_cycle_prioritized_warps.size() < m_max_active_warps ) {
@@ -985,7 +1009,7 @@ void two_level_active_scheduler::order_warps()
(m_next_cycle_prioritized_warps.back())->get_warp_id(),
(m_next_cycle_prioritized_warps.back())->get_dynamic_warp_id() );
++num_promoted;
- }
+ }
} else {
fprintf( stderr,
"Unimplemented m_outer_level_prioritization: %d\n",
@@ -995,6 +1019,42 @@ void two_level_active_scheduler::order_warps()
assert( num_promoted == num_demoted );
}
+swl_scheduler::swl_scheduler ( shader_core_stats* stats, shader_core_ctx* shader,
+ Scoreboard* scoreboard, simt_stack** simt,
+ std::vector<shd_warp_t>* warp,
+ register_set* sp_out,
+ register_set* sfu_out,
+ register_set* mem_out,
+ int id,
+ char* config_string )
+ : scheduler_unit ( stats, shader, scoreboard, simt, warp, sp_out, sfu_out, mem_out, id )
+{
+ int ret = sscanf( config_string,
+ "warp_limiting:%d:%d",
+ (int*)&m_prioritization,
+ &m_num_warps_to_limit
+ );
+ assert( 2 == ret );
+ // Currently only GTO is implemented
+ assert( m_prioritization == SCHEDULER_PRIORITIZATION_GTO );
+ assert( m_num_warps_to_limit <= shader->get_config()->max_warps_per_shader );
+}
+
+void swl_scheduler::order_warps()
+{
+ if ( SCHEDULER_PRIORITIZATION_GTO == m_prioritization ) {
+ order_by_priority( m_next_cycle_prioritized_warps,
+ m_supervised_warps,
+ m_last_supervised_issued,
+ MIN( m_num_warps_to_limit, m_supervised_warps.size() ),
+ ORDERING_GREEDY_THEN_PRIORITY_FUNC,
+ scheduler_unit::sort_warps_by_oldest_dynamic_id );
+ } else {
+ fprintf(stderr, "swl_scheduler m_prioritization = %d\n", m_prioritization);
+ abort();
+ }
+}
+
void shader_core_ctx::read_operands()
{
}
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index 76133e2..7c99ac5 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -279,6 +279,7 @@ enum concrete_scheduler
CONCRETE_SCHEDULER_LRR = 0,
CONCRETE_SCHEDULER_GTO,
CONCRETE_SCHEDULER_TWO_LEVEL_ACTIVE,
+ CONCRETE_SCHEDULER_WARP_LIMITING,
NUM_CONCRETE_SCHEDULERS
};
@@ -452,6 +453,28 @@ private:
unsigned m_max_active_warps;
};
+// Static Warp Limiting Scheduler
+class swl_scheduler : public scheduler_unit {
+public:
+ swl_scheduler ( shader_core_stats* stats, shader_core_ctx* shader,
+ Scoreboard* scoreboard, simt_stack** simt,
+ std::vector<shd_warp_t>* warp,
+ register_set* sp_out,
+ register_set* sfu_out,
+ register_set* mem_out,
+ int id,
+ char* config_string );
+ virtual ~swl_scheduler () {}
+ virtual void order_warps ();
+ virtual void done_adding_supervised_warps() {
+ m_last_supervised_issued = m_supervised_warps.begin();
+ }
+
+protected:
+ scheduler_prioritization_type m_prioritization;
+ unsigned m_num_warps_to_limit;
+};
+
class opndcoll_rfu_t { // operand collector based register file unit