summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/l2cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim/l2cache.cc')
-rw-r--r--src/gpgpu-sim/l2cache.cc340
1 files changed, 270 insertions, 70 deletions
diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc
index a661b4b..d667fd7 100644
--- a/src/gpgpu-sim/l2cache.cc
+++ b/src/gpgpu-sim/l2cache.cc
@@ -43,6 +43,7 @@
#include "gpu-sim.h"
#include "shader.h"
#include "mem_latency_stat.h"
+#include "l2cache_trace.h"
mem_fetch * partition_mf_allocator::alloc(new_addr_type addr, mem_access_type type, unsigned size, bool wr ) const
@@ -62,11 +63,234 @@ mem_fetch * partition_mf_allocator::alloc(new_addr_type addr, mem_access_type ty
memory_partition_unit::memory_partition_unit( unsigned partition_id,
const struct memory_config *config,
class memory_stats_t *stats )
+: m_id(partition_id), m_config(config), m_stats(stats), m_arbitration_metadata(config)
{
- m_id = partition_id;
+ m_dram = new dram_t(m_id,m_config,m_stats,this);
+
+ m_sub_partition = new memory_sub_partition*[m_config->m_n_sub_partition_per_memory_channel];
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ unsigned sub_partition_id = m_id * m_config->m_n_sub_partition_per_memory_channel + p;
+ m_sub_partition[p] = new memory_sub_partition(sub_partition_id, m_config, stats);
+ }
+}
+
+memory_partition_unit::~memory_partition_unit()
+{
+ delete m_dram;
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ delete m_sub_partition[p];
+ }
+ delete[] m_sub_partition;
+}
+
+memory_partition_unit::arbitration_metadata::arbitration_metadata(const struct memory_config *config)
+: m_last_borrower(config->m_n_sub_partition_per_memory_channel - 1),
+ m_private_credit(config->m_n_sub_partition_per_memory_channel, 0),
+ m_shared_credit(0)
+{
+ // each sub partition get at least 1 credit for forward progress
+ // the rest is shared among with other partitions
+ m_private_credit_limit = 1;
+ m_shared_credit_limit = config->gpgpu_frfcfs_dram_sched_queue_size
+ + config->gpgpu_dram_return_queue_size
+ - (config->m_n_sub_partition_per_memory_channel - 1);
+ if (config->gpgpu_frfcfs_dram_sched_queue_size == 0
+ or config->gpgpu_dram_return_queue_size == 0)
+ {
+ m_shared_credit_limit = 0; // no limit if either of the queue has no limit in size
+ }
+ assert(m_shared_credit_limit >= 0);
+}
+
+bool memory_partition_unit::arbitration_metadata::has_credits(int inner_sub_partition_id) const
+{
+ int spid = inner_sub_partition_id;
+ if (m_private_credit[spid] < m_private_credit_limit) {
+ return true;
+ } else if (m_shared_credit_limit == 0 || m_shared_credit < m_shared_credit_limit) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void memory_partition_unit::arbitration_metadata::borrow_credit(int inner_sub_partition_id)
+{
+ int spid = inner_sub_partition_id;
+ if (m_private_credit[spid] < m_private_credit_limit) {
+ m_private_credit[spid] += 1;
+ } else if (m_shared_credit_limit == 0 || m_shared_credit < m_shared_credit_limit) {
+ m_shared_credit += 1;
+ } else {
+ assert(0 && "DRAM arbitration error: Borrowing from depleted credit!");
+ }
+ m_last_borrower = spid;
+}
+
+void memory_partition_unit::arbitration_metadata::return_credit(int inner_sub_partition_id)
+{
+ int spid = inner_sub_partition_id;
+ if (m_private_credit[spid] > 0) {
+ m_private_credit[spid] -= 1;
+ } else {
+ m_shared_credit -= 1;
+ }
+ assert((m_shared_credit >= 0) && "DRAM arbitration error: Returning more than available credits!");
+}
+
+void memory_partition_unit::arbitration_metadata::print( FILE *fp ) const
+{
+ fprintf(fp, "private_credit = ");
+ for (unsigned p = 0; p < m_private_credit.size(); p++) {
+ fprintf(fp, "%d ", m_private_credit[p]);
+ }
+ fprintf(fp, "(limit = %d)\n", m_private_credit_limit);
+ fprintf(fp, "shared_credit = %d (limit = %d)\n", m_shared_credit, m_shared_credit_limit);
+}
+
+bool memory_partition_unit::busy() const
+{
+ bool busy = false;
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ if (m_sub_partition[p]->busy()) {
+ busy = true;
+ }
+ }
+ return busy;
+}
+
+void memory_partition_unit::cache_cycle(unsigned cycle)
+{
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ m_sub_partition[p]->cache_cycle(cycle);
+ }
+}
+
+void memory_partition_unit::visualizer_print( gzFile visualizer_file ) const
+{
+ m_dram->visualizer_print(visualizer_file);
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ m_sub_partition[p]->visualizer_print(visualizer_file);
+ }
+}
+
+// determine whether a given subpartition can issue to DRAM
+bool memory_partition_unit::can_issue_to_dram(int inner_sub_partition_id)
+{
+ int spid = inner_sub_partition_id;
+ bool sub_partition_contention = m_sub_partition[spid]->dram_L2_queue_full();
+ bool has_dram_resource = m_arbitration_metadata.has_credits(spid);
+
+ MEMPART_DPRINTF("sub partition %d sub_partition_contention=%c has_dram_resource=%c\n",
+ spid, (sub_partition_contention)? 'T':'F', (has_dram_resource)? 'T':'F');
+
+ return (has_dram_resource && !sub_partition_contention);
+}
+
+int memory_partition_unit::global_sub_partition_id_to_local_id(int global_sub_partition_id) const
+{
+ return (global_sub_partition_id - m_id * m_config->m_n_sub_partition_per_memory_channel);
+}
+
+void memory_partition_unit::dram_cycle()
+{
+ // pop completed memory request from dram and push it to dram-to-L2 queue
+ // of the original sub partition
+ mem_fetch* mf_return = m_dram->return_queue_top();
+ if (mf_return) {
+ unsigned dest_global_spid = mf_return->get_sub_partition_id();
+ int dest_spid = global_sub_partition_id_to_local_id(dest_global_spid);
+ assert(m_sub_partition[dest_spid]->get_id() == dest_global_spid);
+ if (!m_sub_partition[dest_spid]->dram_L2_queue_full()) {
+ if( mf_return->get_access_type() == L1_WRBK_ACC ) {
+ m_sub_partition[dest_spid]->set_done(mf_return);
+ delete mf_return;
+ } else {
+ m_sub_partition[dest_spid]->dram_L2_queue_push(mf_return);
+ mf_return->set_status(IN_PARTITION_DRAM_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
+ m_arbitration_metadata.return_credit(dest_spid);
+ MEMPART_DPRINTF("mem_fetch request %p return from dram to sub partition %d\n", mf_return, dest_spid);
+ }
+ m_dram->return_queue_pop();
+ }
+ } else {
+ m_dram->return_queue_pop();
+ }
+
+ m_dram->cycle();
+ m_dram->dram_log(SAMPLELOG);
+
+ if( !m_dram->full() ) {
+ // L2->DRAM queue to DRAM latency queue
+ // Arbitrate among multiple L2 subpartitions
+ int last_issued_partition = m_arbitration_metadata.last_borrower();
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ int spid = (p + last_issued_partition + 1) % m_config->m_n_sub_partition_per_memory_channel;
+ if (!m_sub_partition[spid]->L2_dram_queue_empty() && can_issue_to_dram(spid)) {
+ mem_fetch *mf = m_sub_partition[spid]->L2_dram_queue_top();
+ m_sub_partition[spid]->L2_dram_queue_pop();
+ MEMPART_DPRINTF("Issue mem_fetch request %p from sub partition %d to dram\n", mf, spid);
+ dram_delay_t d;
+ d.req = mf;
+ d.ready_cycle = gpu_sim_cycle+gpu_tot_sim_cycle + m_config->dram_latency;
+ m_dram_latency_queue.push(d);
+ mf->set_status(IN_PARTITION_DRAM_LATENCY_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
+ m_arbitration_metadata.borrow_credit(spid);
+ break; // the DRAM should only accept one request per cycle
+ }
+ }
+ }
+
+ // DRAM latency queue
+ if( !m_dram_latency_queue.empty() && ( (gpu_sim_cycle+gpu_tot_sim_cycle) >= m_dram_latency_queue.front().ready_cycle ) && !m_dram->full() ) {
+ mem_fetch* mf = m_dram_latency_queue.front().req;
+ m_dram_latency_queue.pop();
+ m_dram->push(mf);
+ }
+}
+
+void memory_partition_unit::set_done( mem_fetch *mf )
+{
+ unsigned global_spid = mf->get_sub_partition_id();
+ int spid = global_sub_partition_id_to_local_id(global_spid);
+ assert(m_sub_partition[spid]->get_id() == global_spid);
+ if (mf->get_access_type() == L1_WRBK_ACC || mf->get_access_type() == L2_WRBK_ACC) {
+ m_arbitration_metadata.return_credit(spid);
+ MEMPART_DPRINTF("mem_fetch request %p return from dram to sub partition %d\n", mf, spid);
+ }
+ m_sub_partition[spid]->set_done(mf);
+}
+
+void memory_partition_unit::set_dram_power_stats(unsigned &n_cmd,
+ unsigned &n_activity,
+ unsigned &n_nop,
+ unsigned &n_act,
+ unsigned &n_pre,
+ unsigned &n_rd,
+ unsigned &n_wr,
+ unsigned &n_req) const
+{
+ m_dram->set_dram_power_stats(n_cmd, n_activity, n_nop, n_act, n_pre, n_rd, n_wr, n_req);
+}
+
+void memory_partition_unit::print( FILE *fp ) const
+{
+ fprintf(fp, "Memory Partition %u: \n", m_id);
+ for (unsigned p = 0; p < m_config->m_n_sub_partition_per_memory_channel; p++) {
+ m_sub_partition[p]->print(fp);
+ }
+ m_dram->print(fp);
+}
+
+memory_sub_partition::memory_sub_partition( unsigned sub_partition_id,
+ const struct memory_config *config,
+ class memory_stats_t *stats )
+{
+ m_id = sub_partition_id;
m_config=config;
m_stats=stats;
- m_dram = new dram_t(m_id,m_config,m_stats,this);
+
+ assert(m_id < m_config->m_n_mem_sub_partition);
char L2c_name[32];
snprintf(L2c_name, 32, "L2_bank_%03d", m_id);
@@ -88,7 +312,7 @@ memory_partition_unit::memory_partition_unit( unsigned partition_id,
wb_addr=-1;
}
-memory_partition_unit::~memory_partition_unit()
+memory_sub_partition::~memory_sub_partition()
{
delete m_icnt_L2_queue;
delete m_L2_dram_queue;
@@ -98,7 +322,7 @@ memory_partition_unit::~memory_partition_unit()
delete m_L2interface;
}
-void memory_partition_unit::cache_cycle( unsigned cycle )
+void memory_sub_partition::cache_cycle( unsigned cycle )
{
// L2 fill responses
if( !m_config->m_L2_config.disabled()) {
@@ -189,22 +413,47 @@ void memory_partition_unit::cache_cycle( unsigned cycle )
}
}
-bool memory_partition_unit::full() const
+bool memory_sub_partition::full() const
{
return m_icnt_L2_queue->full();
}
-void memory_partition_unit::print_cache_stat(unsigned &accesses, unsigned &misses) const
+bool memory_sub_partition::L2_dram_queue_empty() const
+{
+ return m_L2_dram_queue->empty();
+}
+
+class mem_fetch* memory_sub_partition::L2_dram_queue_top() const
+{
+ return m_L2_dram_queue->top();
+}
+
+void memory_sub_partition::L2_dram_queue_pop()
+{
+ m_L2_dram_queue->pop();
+}
+
+bool memory_sub_partition::dram_L2_queue_full() const
+{
+ return m_dram_L2_queue->full();
+}
+
+void memory_sub_partition::dram_L2_queue_push( class mem_fetch* mf )
+{
+ m_dram_L2_queue->push(mf);
+}
+
+void memory_sub_partition::print_cache_stat(unsigned &accesses, unsigned &misses) const
{
FILE *fp = stdout;
if( !m_config->m_L2_config.disabled() )
m_L2cache->print(fp,accesses,misses);
}
-void memory_partition_unit::print( FILE *fp ) const
+void memory_sub_partition::print( FILE *fp ) const
{
if ( !m_request_tracker.empty() ) {
- fprintf(fp,"Memory Parition %u: pending memory requests:\n", m_id);
+ fprintf(fp,"Memory Sub Parition %u: pending memory requests:\n", m_id);
for ( std::set<mem_fetch*>::const_iterator r=m_request_tracker.begin(); r != m_request_tracker.end(); ++r ) {
mem_fetch *mf = *r;
if ( mf )
@@ -215,7 +464,6 @@ void memory_partition_unit::print( FILE *fp ) const
}
if( !m_config->m_L2_config.disabled() )
m_L2cache->display_state(fp);
- m_dram->print(fp);
}
void memory_stats_t::visualizer_print( gzFile visualizer_file )
@@ -264,26 +512,19 @@ void gpgpu_sim::print_dram_stats(FILE *fout) const
fprintf(fout,"gpgpu_n_dram_precharges = %d\n",tot_pre );
fprintf(fout,"gpgpu_n_dram_requests = %d\n",tot_req );
}
-void gpgpu_sim::L2c_print_cache_stat() const
-{
- unsigned i, j, k;
- for (i=0,j=0,k=0;i<m_memory_config->m_n_mem;i++)
- m_memory_partition_unit[i]->print_cache_stat(k,j);
- printf("L2 Cache Total Miss Rate = %0.3f\n", (float)j/k);
-}
-unsigned memory_partition_unit::flushL2()
+unsigned memory_sub_partition::flushL2()
{
m_L2cache->flush();
return 0; // L2 is read only in this version
}
-bool memory_partition_unit::busy() const
+bool memory_sub_partition::busy() const
{
return !m_request_tracker.empty();
}
-void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle )
+void memory_sub_partition::push( mem_fetch* req, unsigned long long cycle )
{
if (req) {
m_request_tracker.insert(req);
@@ -301,7 +542,7 @@ void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle )
}
}
-mem_fetch* memory_partition_unit::pop()
+mem_fetch* memory_sub_partition::pop()
{
mem_fetch* mf = m_L2_icnt_queue->pop();
m_request_tracker.erase(mf);
@@ -314,7 +555,7 @@ mem_fetch* memory_partition_unit::pop()
return mf;
}
-mem_fetch* memory_partition_unit::top()
+mem_fetch* memory_sub_partition::top()
{
mem_fetch *mf = m_L2_icnt_queue->top();
if( mf && (mf->get_access_type() == L2_WRBK_ACC || mf->get_access_type() == L1_WRBK_ACC) ) {
@@ -326,62 +567,21 @@ mem_fetch* memory_partition_unit::top()
return mf;
}
-void memory_partition_unit::set_done( mem_fetch *mf )
+void memory_sub_partition::set_done( mem_fetch *mf )
{
m_request_tracker.erase(mf);
}
-void memory_partition_unit::dram_cycle()
-{
- // pop completed memory request from dram and push it to dram-to-L2 queue
- if ( !m_dram_L2_queue->full() ) {
- mem_fetch* mf = m_dram->pop();
- if (mf) {
- if( mf->get_access_type() == L1_WRBK_ACC ) {
- m_request_tracker.erase(mf);
- delete mf;
- } else {
- m_dram_L2_queue->push(mf);
- mf->set_status(IN_PARTITION_DRAM_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
- }
- }
- }
- m_dram->cycle();
- m_dram->dram_log(SAMPLELOG);
-
- if( !m_dram->full() && !m_L2_dram_queue->empty() ) {
- // L2->DRAM queue to DRAM latency queue
- mem_fetch *mf = m_L2_dram_queue->pop();
- dram_delay_t d;
- d.req = mf;
- d.ready_cycle = gpu_sim_cycle+gpu_tot_sim_cycle + m_config->dram_latency;
- m_dram_latency_queue.push(d);
- mf->set_status(IN_PARTITION_DRAM_LATENCY_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle);
- }
-
- // DRAM latency queue
- if( !m_dram_latency_queue.empty() && ( (gpu_sim_cycle+gpu_tot_sim_cycle) >= m_dram_latency_queue.front().ready_cycle ) && !m_dram->full() ) {
- mem_fetch* mf = m_dram_latency_queue.front().req;
- m_dram_latency_queue.pop();
- m_dram->push(mf);
- }
+void memory_sub_partition::accumulate_L2cache_stats(class cache_stats &l2_stats) const {
+ l2_stats += m_L2cache->get_stats();
}
-void memory_partition_unit::set_dram_power_stats(unsigned &n_cmd,
- unsigned &n_activity,
- unsigned &n_nop,
- unsigned &n_act,
- unsigned &n_pre,
- unsigned &n_rd,
- unsigned &n_wr,
- unsigned &n_req) const{
- m_dram->set_dram_power_stats(n_cmd, n_activity, n_nop, n_act, n_pre, n_rd, n_wr, n_req);
+void memory_sub_partition::get_L2cache_sub_stats(struct cache_sub_stats &css) const{
+ m_L2cache->get_sub_stats(css);
}
-void memory_partition_unit::accumulate_L2cache_stats(class cache_stats &l2_stats) const {
- l2_stats += m_L2cache->get_stats();
+void memory_sub_partition::visualizer_print( gzFile visualizer_file )
+{
+ // TODO: Add visualizer stats for L2 cache
}
-void memory_partition_unit::get_L2cache_sub_stats(struct cache_sub_stats &css) const{
- m_L2cache->get_sub_stats(css);
-}