diff options
Diffstat (limited to 'src/gpgpu-sim/l2cache.cc')
| -rw-r--r-- | src/gpgpu-sim/l2cache.cc | 340 |
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); -} |
