From 87e4da5fc6086c3d0a661af1929255a8cbd728d7 Mon Sep 17 00:00:00 2001 From: Tor Aamodt Date: Mon, 18 Oct 2010 02:43:17 -0800 Subject: Re-designed cache model: - read only cache model with integrated mshrs (no L1D, yet); new cache interface should be easily extendable to support texture cache with latency fifo and separate tag/data arrays, though this is not yet added (currently tags and data arrays are not decoupled for texture) - new partition model using the above removes all old MSHRs, L1D etc... passing CUDA 3.1 regression [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7875] --- src/gpgpu-sim/l2cache.cc | 746 ++++++++++------------------------------------- 1 file changed, 154 insertions(+), 592 deletions(-) (limited to 'src/gpgpu-sim/l2cache.cc') diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index d2b61d7..634fa55 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -83,649 +83,211 @@ #include "shader.h" #include "mem_latency_stat.h" -template class fifo_pipeline; - -address_type L2c_mshr::cache_tag(const mem_fetch *mf) const -{ - return (mf->get_addr() & ~(m_linesize - 1)); -} - -address_type L2c_miss_tracker::cache_tag(const mem_fetch *mf) const -{ - return (mf->get_addr() & ~(m_linesize - 1)); -} - -address_type L2c_access_locality::cache_tag(const mem_fetch *mf) const -{ - return (mf->get_addr() & ~(m_linesize - 1)); -} - void gpgpu_sim::L2c_options(option_parser_t opp) { - option_parser_register(opp, "-gpgpu_L2_queue", OPT_CSTR, &m_memory_config->gpgpu_L2_queue_config, - "L2 data cache queue length and latency config", - "0:0:0:0:0:0:10:10"); - - option_parser_register(opp, "-gpgpu_l2_readoverwrite", OPT_BOOL, &m_memory_config->gpgpu_l2_readoverwrite, - "Prioritize read requests over write requests for L2", - "0"); - - option_parser_register(opp, "-l2_ideal", OPT_BOOL, &m_memory_config->l2_ideal, - "Use a ideal L2 cache that always hit", - "0"); -} - - -//////////////////////////////////////////////// -// L2 MSHR model - -bool L2c_mshr::new_miss(const mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - mem_fetch_list &missGroup = m_L2missgroup[cacheTag]; - - bool mshr_hit = not missGroup.empty(); - - missGroup.push_front(mf); - - m_n_miss += 1; - if (mshr_hit) - m_n_mshr_hits += 1; - m_entries_used += 1; - m_max_entries_used = std::max(m_max_entries_used, m_entries_used); - - return mshr_hit; -} - -void L2c_mshr::miss_serviced(const mem_fetch *mf) -{ - assert(m_active_mshr_chain.list == NULL); - address_type cacheTag = cache_tag(mf); - L2missGroup::iterator missGroup = m_L2missgroup.find(cacheTag); - if (missGroup == m_L2missgroup.end() || mf->get_type() == L2_WTBK_DATA) { - assert(mf->get_type() == L2_WTBK_DATA); // only this returning mem req can be missed by the MSHR - return; - } - assert(missGroup->first == cacheTag); - - m_active_mshr_chain.cacheTag = cacheTag; - m_active_mshr_chain.list = &(missGroup->second); - - m_n_miss_serviced_by_dram += 1; -} - -bool L2c_mshr::mshr_chain_empty() -{ - return (m_active_mshr_chain.list == NULL); -} - -mem_fetch *L2c_mshr::mshr_chain_top() -{ - const mem_fetch *mf = m_active_mshr_chain.list->back(); - assert(cache_tag(mf) == m_active_mshr_chain.cacheTag); - - return const_cast(mf); -} - -void L2c_mshr::mshr_chain_pop() -{ - m_entries_used -= 1; - m_active_mshr_chain.list->pop_back(); - if (m_active_mshr_chain.list->empty()) { - address_type cacheTag = m_active_mshr_chain.cacheTag; - m_L2missgroup.erase(cacheTag); - m_active_mshr_chain.list = NULL; - } -} - -void L2c_mshr::print(FILE *fout) -{ - fprintf(fout, "L2c MSHR: n_entries_used = %zu\n", m_entries_used); - L2missGroup::iterator missGroup; - for (missGroup = m_L2missgroup.begin(); missGroup != m_L2missgroup.end(); ++missGroup) { - fprintf(fout, "%#08x: ", missGroup->first); - mem_fetch_list &mf_list = missGroup->second; - for (mem_fetch_list::iterator imf = mf_list.begin(); imf != mf_list.end(); ++imf) - (*imf)->print(fout); - fprintf(fout, "\n"); - } -} - -void L2c_mshr::print_stat(FILE *fout) const -{ - fprintf(fout, "L2c MSHR: max_entry = %zu, n_miss = %d, n_mshr_hits = %d, n_serviced_by_dram %d\n", - m_max_entries_used, m_n_miss, m_n_mshr_hits, m_n_miss_serviced_by_dram); -} - -//////////////////////////////////////////////// -// track redundant dram access generated by L2 cache - -void L2c_miss_tracker::new_miss(mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - mem_fetch_set &missGroup = m_L2missgroup[cacheTag]; - - if (missGroup.size() != 0) { - m_L2redundantCnt[cacheTag] += 1; - m_totalL2redundantAcc += 1; - } - - missGroup.insert(mf); -} - -void L2c_miss_tracker::miss_serviced(mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - L2missGroup::iterator iMissGroup = m_L2missgroup.find(cacheTag); - if (iMissGroup == m_L2missgroup.end()) return; // this is possible for write miss - mem_fetch_set &missGroup = iMissGroup->second; - - missGroup.erase(mf); - - // remove the miss group if it goes empty - if (missGroup.empty()) { - m_L2missgroup.erase(iMissGroup); - } -} - -void L2c_miss_tracker::print(FILE *fout, bool brief) -{ - L2missGroup::iterator iMissGroup; - for (iMissGroup = m_L2missgroup.begin(); iMissGroup != m_L2missgroup.end(); ++iMissGroup) { - fprintf(fout, "%#08x: ", iMissGroup->first); - for (mem_fetch_set::iterator iMemSet = iMissGroup->second.begin(); iMemSet != iMissGroup->second.end(); ++iMemSet) { - fprintf(fout, "%p ", *iMemSet); - } - fprintf(fout, "\n"); - } -} - -void L2c_miss_tracker::print_stat(FILE *fout, bool brief) const -{ - fprintf(fout, "RedundantMiss = %d\n", m_totalL2redundantAcc); - if (brief == true) return; - fprintf(fout, " Detail:"); - for (L2redundantCnt::const_iterator iL2rc = m_L2redundantCnt.begin(); iL2rc != m_L2redundantCnt.end(); ++iL2rc) { - fprintf(fout, "%#08x:%d ", iL2rc->first, iL2rc->second); - } - fprintf(fout, "\n"); -} - -//////////////////////////////////////////////// -// track all locality of L2 cache access -void L2c_access_locality::access(mem_fetch *mf) -{ - address_type cacheTag = cache_tag(mf); - m_L2accCnt[cacheTag] += 1; - m_totalL2accAcc += 1; -} - -void L2c_access_locality::print_stat(FILE *fout, bool brief) const -{ - float access_locality = (float) m_totalL2accAcc / m_L2accCnt.size(); - fprintf(fout, "Access Locality = %d / %zu (%f) \n", m_totalL2accAcc, m_L2accCnt.size(), access_locality); - if (brief == true) return; - fprintf(fout, " Detail:"); - pow2_histogram locality_histo(" Hits"); - for (L2accCnt::const_iterator iL2rc = m_L2accCnt.begin(); iL2rc != m_L2accCnt.end(); ++iL2rc) { - locality_histo.add2bin(iL2rc->second); - } - locality_histo.fprint(fout); - fprintf(fout, "\n"); -} - -memory_partition_unit::~memory_partition_unit() -{ - delete m_mshr; - delete m_missTracker; - delete m_accessLocality; -} - -void memory_partition_unit::cache_cycle() -{ - process_dram_output(); // pop from dram - L2c_push_miss_to_dram(); // push to dram - L2c_service_mem_req(); // pop(push) from(to) icnt2l2(l2toicnt) queues; service l2 requests - if (m_config->m_L2_config.get_num_lines()) { // L2 cache enabled - L2c_update_stat(); - L2c_log(SAMPLELOG); - } -} - -unsigned memory_partition_unit::L2c_get_linesize() -{ - return m_config->m_L2_config.get_line_sz(); -} + option_parser_register(opp, "-gpgpu_dram_partition_queues", OPT_CSTR, &m_memory_config->gpgpu_L2_queue_config, + "i2$:$2d:d2$:$2i", + "8:8:8:8"); -bool memory_partition_unit::full() const -{ - if (m_config->m_L2_config.get_num_lines()) { - return m_icnt2cache_queue->full() || m_icnt2cache_write_queue->full(); - } else { - return( m_config->gpgpu_dram_sched_queue_size && m_dram->full() ); - } + option_parser_register(opp, "-l2_ideal", OPT_BOOL, &m_memory_config->l2_ideal, + "Use a ideal L2 cache that always hit", + "0"); } -//////////////////////////////////////////////// -// L2 access functions +////////// -// L2 Cache Creation memory_partition_unit::memory_partition_unit( unsigned partition_id, struct memory_config *config, class memory_stats_t *stats ) { - m_id = partition_id; - m_config=config; - m_stats=stats; - m_dram = new dram_t(m_id,m_config,m_stats); - - if( m_config->m_L2_config.get_num_lines() ) { - char L2c_name[32]; - snprintf(L2c_name, 32, "L2_bank_%03d", m_id); - m_L2cache = new cache_t(L2c_name,m_config->m_L2_config,-1,-1); - unsigned l2_line_sz = m_config->m_L2_config.get_line_sz(); - m_mshr = new L2c_mshr( l2_line_sz ); - m_missTracker = new L2c_miss_tracker( l2_line_sz ); - m_accessLocality = new L2c_access_locality( l2_line_sz ); - } else { - m_L2cache=NULL; - m_mshr=NULL; - m_missTracker=NULL; - m_accessLocality=NULL; - } + m_id = partition_id; + m_config=config; + m_stats=stats; + m_dram = new dram_t(m_id,m_config,m_stats); - unsigned int L2c_cb_L2_length; - unsigned int L2c_cb_L2w_length; - unsigned int L2c_L2_dm_length; - unsigned int L2c_dm_L2_length; - unsigned int L2c_dm_L2w_length; - unsigned int L2c_L2_cb_length; - unsigned int L2c_L2_cb_minlength; - unsigned int L2c_L2_dm_minlength; + char L2c_name[32]; + snprintf(L2c_name, 32, "L2_bank_%03d", m_id); + m_L2interface = new L2interface(this); + m_L2cache = new cache_t(L2c_name,m_config->m_L2_config,-1,-1,m_L2interface); - sscanf(m_config->gpgpu_L2_queue_config,"%d:%d:%d:%d:%d:%d:%d:%d", - &L2c_cb_L2_length, &L2c_cb_L2w_length, &L2c_L2_dm_length, - &L2c_dm_L2_length, &L2c_dm_L2w_length, &L2c_L2_cb_length, - &L2c_L2_cb_minlength, &L2c_L2_dm_minlength ); - //(,,,) - m_icnt2cache_queue = new fifo_pipeline("cbtoL2queue", 0,L2c_cb_L2_length, gpu_sim_cycle); - m_icnt2cache_write_queue = new fifo_pipeline("cbtoL2writequeue", 0,L2c_cb_L2w_length, gpu_sim_cycle); - L2todramqueue = new fifo_pipeline("L2todramqueue", L2c_L2_dm_minlength, L2c_L2_dm_length, gpu_sim_cycle); - dramtoL2queue = new fifo_pipeline("dramtoL2queue", 0,L2c_dm_L2_length, gpu_sim_cycle); - dramtoL2writequeue = new fifo_pipeline("dramtoL2writequeue",0,L2c_dm_L2w_length, gpu_sim_cycle); - L2tocbqueue = new fifo_pipeline("L2tocbqueue", L2c_L2_cb_minlength, L2c_L2_cb_length, gpu_sim_cycle); - L2todram_wbqueue = new fifo_pipeline("L2todram_wbqueue", L2c_L2_dm_minlength, L2c_L2_dm_minlength + m_config->gpgpu_dram_sched_queue_size + L2c_dm_L2_length, gpu_sim_cycle); - L2dramout = NULL; - wb_addr=-1; - if (m_config->m_L2_config.get_num_lines() && 1) { - cbtol2_Dist = StatCreate("cbtoL2",1, m_icnt2cache_queue->get_max_len()); - cbtoL2wr_Dist = StatCreate("cbtoL2write",1, m_icnt2cache_write_queue->get_max_len()); - L2tocb_Dist = StatCreate("L2tocb",1, L2tocbqueue->get_max_len()); - dramtoL2_Dist = StatCreate("dramtoL2",1, dramtoL2queue->get_max_len()); - dramtoL2wr_Dist = StatCreate("dramtoL2write",1, dramtoL2writequeue->get_max_len()); - L2todram_Dist = StatCreate("L2todram",1, L2todramqueue->get_max_len()); - L2todram_wb_Dist = StatCreate("L2todram_wb",1, L2todram_wbqueue->get_max_len()); - } else { - cbtol2_Dist = NULL; - cbtoL2wr_Dist = NULL; - L2tocb_Dist = NULL; - dramtoL2_Dist = NULL; - dramtoL2wr_Dist = NULL; - L2todram_Dist = NULL; - L2todram_wb_Dist = NULL; - } -} + unsigned int icnt_L2; + unsigned int L2_dram; + unsigned int dram_L2; + unsigned int L2_icnt; -void memory_partition_unit::L2c_service_mem_req() -{ - // service memory request in icnt-to-L2 queue, writing to L2 as necessary - if( L2tocbqueue->full() || L2todramqueue->full() ) - return; - mem_fetch* mf = m_icnt2cache_queue->pop(gpu_sim_cycle); - if( !mf ) - mf = m_icnt2cache_write_queue->pop(gpu_sim_cycle); - if( !mf ) - return; - switch (mf->get_type()) { - case RD_REQ: - case WT_REQ: { - address_type rep_block; - enum cache_request_status status = MISS_NO_WB; - if( mf->istexture() ) - status = m_L2cache->access( mf->get_partition_addr(), mf->get_is_write(), gpu_sim_cycle, &rep_block); - if( (status==HIT) || m_config->l2_ideal ) { - mf->set_type( REPLY_DATA ); - assert( mf != NULL ); - L2tocbqueue->push(mf,gpu_sim_cycle); - if (!mf->get_is_write()) { - m_stats->L2_read_hit++; - mf->set_return_timestamp(gpu_sim_cycle+gpu_tot_sim_cycle); - mf->set_status(IN_L2TOCBQUEUE_HIT,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } else { - m_stats->L2_write_hit++; - } - } else { - // L2 Cache Miss - // if a miss hits in the mshr, that means there is another inflight request for the same data - // this miss just need to access the cache later when this request is serviced - bool mshr_hit = m_mshr->new_miss(mf); - if (not mshr_hit) - L2todramqueue->push(mf,gpu_sim_cycle); - mf->set_status(IN_L2TODRAMQUEUE,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - } - } - break; - default: assert(0); - } + sscanf(m_config->gpgpu_L2_queue_config,"%u:%u:%u:%u", &icnt_L2,&L2_dram,&dram_L2,&L2_icnt ); + m_icnt_L2_queue = new fifo_pipeline("icnt-to-L2",0,icnt_L2); + m_L2_dram_queue = new fifo_pipeline("L2-to-dram",0,L2_dram); + m_dram_L2_queue = new fifo_pipeline("dram-to-L2",0,dram_L2); + m_L2_icnt_queue = new fifo_pipeline("L2-to-icnt",0,L2_icnt); + wb_addr=-1; } -// service memory request in L2todramqueue, pushing to dram -void memory_partition_unit::L2c_push_miss_to_dram() +memory_partition_unit::~memory_partition_unit() { - if ( m_config->gpgpu_dram_sched_queue_size && m_dram->full() ) - return; - mem_fetch* mf = L2todram_wbqueue->pop(gpu_sim_cycle); //prioritize writeback - if (!mf) mf = L2todramqueue->pop(gpu_sim_cycle); - if (mf) { - if (mf->get_is_write()) - m_stats->L2_write_miss++; - else - m_stats->L2_read_miss++; - m_missTracker->new_miss(mf); - m_dram->push(mf); - mf->set_status(IN_DRAM_REQ_QUEUE, MR_DRAMQ, gpu_sim_cycle+gpu_tot_sim_cycle); - } + delete m_icnt_L2_queue; + delete m_L2_dram_queue; + delete m_dram_L2_queue; + delete m_L2_icnt_queue; + delete m_L2cache; + delete m_L2interface; } -// service memory request in dramtoL2queue, writing to L2 as necessary -// (may cause cache eviction and subsequent writeback) -void memory_partition_unit::process_dram_output() +void memory_partition_unit::cache_cycle() { - if (L2dramout == NULL) { - // pop from mshr chain if it is not empty, otherwise, pop a new cacheline from dram output queue - if (m_mshr->mshr_chain_empty() == false) { - L2dramout = m_mshr->mshr_chain_top(); - m_mshr->mshr_chain_pop(); - } else { - L2dramout = dramtoL2queue->pop(gpu_sim_cycle); - if (!L2dramout) - L2dramout = dramtoL2writequeue->pop(gpu_sim_cycle); - if (L2dramout != NULL) { - m_mshr->miss_serviced(L2dramout); - if (m_mshr->mshr_chain_empty() == false) { // possible if this is a L2 writeback - L2dramout = m_mshr->mshr_chain_top(); - m_mshr->mshr_chain_pop(); - } - } - } - } - mem_fetch* mf = L2dramout; - if (mf) { - if (!mf->get_is_write()) { //service L2 read miss - // it is a pre-fill dramout mf - if (wb_addr == (unsigned long long int)-1) { - if ( L2tocbqueue->full() ) { - assert (L2dramout || wb_addr == (unsigned long long int)-1); - return; + // L2 fill responses + if ( m_L2cache->access_ready() && !m_L2_icnt_queue->full() ) { + mem_fetch *mf = m_L2cache->next_access(); + mf->set_type(REPLY_DATA); + mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_icnt_queue->push(mf); + } + // DRAM to L2 (texture) and icnt (not texture) + if ( !m_dram_L2_queue->empty() ) { + mem_fetch *mf = m_dram_L2_queue->top(); + if ( mf->istexture() ) { + mf->set_status(IN_PARTITION_L2_FILL_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2cache->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); + m_dram_L2_queue->pop(); + } else if ( !m_L2_icnt_queue->full() ) { + mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_icnt_queue->push(mf); + m_dram_L2_queue->pop(); + } + } + + // prior L2 misses inserted into m_L2_dram_queue here + m_L2cache->cycle(); + + // new L2 texture accesses and/or non-texture accesses + if ( !m_L2_dram_queue->full() && !m_icnt_L2_queue->empty() ) { + mem_fetch *mf = m_icnt_L2_queue->top(); + if ( mf->istexture() ) { + // in this model, L2 is for texture only + if ( !m_L2_icnt_queue->full() ) { + enum cache_request_status status = m_L2cache->access(mf->get_partition_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle); + if ( status == HIT ) { + // L2 cache replies with data + mf->set_type(REPLY_DATA); + m_L2_icnt_queue->push(mf); + m_icnt_L2_queue->pop(); + } else if ( status != RESERVATION_FAIL ) { + // L2 cache accepted request + m_icnt_L2_queue->pop(); + } else { + // L2 cache lock-up: will try again next cycle + } } - mf->set_status(IN_L2TOCBQUEUE_MISS,MR_DRAM_OUTQ,gpu_sim_cycle+gpu_tot_sim_cycle); - //only transfer across icnt once the whole line has been received by L2 cache - mf->set_type(REPLY_DATA); - L2tocbqueue->push(mf,gpu_sim_cycle); - if( mf->istexture() ) - wb_addr = m_L2cache->fill(mf->get_partition_addr(), gpu_sim_cycle); - } - // only perform a write on cache eviction (write-back policy) - // it is the 1st or nth time trial to writeback - if (wb_addr != (unsigned long long int)-1) { - // performing L2 writeback (no false sharing for memory-side cache) - int wb_succeed = L2c_write_back(wb_addr, m_config->m_L2_config.get_line_sz()); - if (!wb_succeed) { - assert (L2dramout || wb_addr == (unsigned long long int)-1); - return; - } - } - m_missTracker->miss_serviced(mf); - L2dramout = NULL; - wb_addr = -1; - } else { //service L2 write miss - m_missTracker->miss_serviced(mf); - mf->set_type(REPLY_DATA); - L2tocbqueue->push(mf,gpu_sim_cycle); - L2dramout = NULL; - wb_addr = -1; - } - } - assert (L2dramout || wb_addr == (unsigned long long int)-1); + } else { + // non-texture access + mf->set_status(IN_PARTITION_L2_TO_DRAM_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_dram_queue->push(mf); + m_icnt_L2_queue->pop(); + } + } } -// Writeback from L2 to DRAM: -// - Takes in memory address and their parameters and pushes to dram request queue -// - This is used only for L2 writeback -bool memory_partition_unit::L2c_write_back( unsigned long long int addr, int bsize ) +bool memory_partition_unit::full() const { - if ( L2todram_wbqueue->full() ) - return false; - mem_fetch *mf = new mem_fetch(addr, - bsize, - READ_PACKET_SIZE, - (unsigned)-1/*sid*/, - (unsigned)-1/*tpc*/, - (unsigned)-1/*wid*/, - (unsigned)-1/*mshr_id*/, - NULL/*inst*/, - true/*write*/, - partial_write_mask_t(), - L2_WRBK_ACC, - L2_WTBK_DATA, - m_config ); - L2todram_wbqueue->push(mf,gpu_sim_cycle); - return true; + return m_icnt_L2_queue->full(); } -void memory_partition_unit::L2c_print_cache_stat(unsigned &accesses, unsigned &misses) const +void memory_partition_unit::print_cache_stat(unsigned &accesses, unsigned &misses) const { - FILE *fp = stdout; - m_L2cache->print(fp,accesses,misses); - m_mshr->print_stat(fp); - m_missTracker->print_stat(fp); - m_accessLocality->print_stat(fp, false); + FILE *fp = stdout; + m_L2cache->print(fp,accesses,misses); } void memory_partition_unit::print( FILE *fp ) const { - if( !m_request_tracker.empty() ) { - fprintf(fp,"Memory Parition %u: pending memory requests:\n", m_id); - for( std::set::const_iterator r=m_request_tracker.begin(); r != m_request_tracker.end(); ++r ) { - mem_fetch *mf = *r; - if( mf ) - mf->print(fp); - else - fprintf(fp," \n"); - } - } - m_dram->print(fp); -} - -void memory_partition_unit::L2c_update_stat() -{ - unsigned i=m_id; - if (m_icnt2cache_queue->get_length() > m_stats->L2_cbtoL2length[i]) - m_stats->L2_cbtoL2length[i] = m_icnt2cache_queue->get_length(); - if (m_icnt2cache_write_queue->get_length() > m_stats->L2_cbtoL2writelength[i]) - m_stats->L2_cbtoL2writelength[i] = m_icnt2cache_write_queue->get_length(); - if (L2tocbqueue->get_length() > m_stats->L2_L2tocblength[i]) - m_stats->L2_L2tocblength[i] = L2tocbqueue->get_length(); - if (dramtoL2queue->get_length() > m_stats->L2_dramtoL2length[i]) - m_stats->L2_dramtoL2length[i] = dramtoL2queue->get_length(); - if (dramtoL2writequeue->get_length() > m_stats->L2_dramtoL2writelength[i]) - m_stats->L2_dramtoL2writelength[i] = dramtoL2writequeue->get_length(); - if (L2todramqueue->get_length() > m_stats->L2_L2todramlength[i]) - m_stats->L2_L2todramlength[i] = L2todramqueue->get_length(); -} - -void memory_stats_t::L2c_print_stat( unsigned n_mem ) -{ - unsigned i; - - printf(" "); - for (i=0;i::const_iterator r=m_request_tracker.begin(); r != m_request_tracker.end(); ++r ) { + mem_fetch *mf = *r; + if ( mf ) + mf->print(fp); + else + fprintf(fp," \n"); + } + } + m_dram->print(fp); } void memory_stats_t::print( FILE *fp ) { - fprintf(fp,"L2_write_miss = %d\n", L2_write_miss); - fprintf(fp,"L2_write_hit = %d\n", L2_write_hit); - fprintf(fp,"L2_read_miss = %d\n", L2_read_miss); - fprintf(fp,"L2_read_hit = %d\n", L2_read_hit); + fprintf(fp,"L2_write_miss = %d\n", L2_write_miss); + fprintf(fp,"L2_write_hit = %d\n", L2_write_hit); + fprintf(fp,"L2_read_miss = %d\n", L2_read_miss); + fprintf(fp,"L2_read_hit = %d\n", L2_read_hit); } void gpgpu_sim::L2c_print_cache_stat() const { - unsigned i, j, k; - for (i=0,j=0,k=0;im_n_mem;i++) - m_memory_partition_unit[i]->L2c_print_cache_stat(k,j); - printf("L2 Cache Total Miss Rate = %0.3f\n", (float)j/k); + unsigned i, j, k; + for (i=0,j=0,k=0;im_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); } -void gpgpu_sim::L2c_print_debug() -{ - unsigned i; - - printf(" "); - for (i=0;im_n_mem;i++) - printf(" dram[%d]", i); - printf("\n"); - - printf("cbtoL2 queue length ="); - for (i=0;im_n_mem;i++) - printf("%8d", m_memory_partition_unit[i]->get_cbtoL2queue_length() ); - printf("\n"); - - printf("cbtoL2 write queue length ="); - for (i=0;im_n_mem;i++) - printf("%8d", m_memory_partition_unit[i]->get_cbtoL2writequeue_length()); - printf("\n"); - - printf("L2tocb queue length ="); - for (i=0;im_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_L2tocbqueue_length()); - } - printf("\n"); - - printf("dramtoL2 queue length ="); - for (i=0;im_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_dramtoL2queue_length()); - } - printf("\n"); - - printf("dramtoL2 write queue length ="); - for (i=0;im_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_dramtoL2writequeue_length()); - } - printf("\n"); - - printf("L2todram queue length ="); - for (i=0;im_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_L2todramqueue_length()); - } - printf("\n"); - - printf("L2todram writeback queue length ="); - for (i=0;im_n_mem;i++) { - printf("%8d", m_memory_partition_unit[i]->get_L2todram_wbqueue_length()); - } - printf("\n"); +unsigned memory_partition_unit::flushL2() +{ + m_L2cache->flush(); + return 0; // L2 is read only in this version } -#define CREATELOG 111 -#define SAMPLELOG 222 -#define DUMPLOG 333 - -void memory_partition_unit::L2c_log(int task) +bool memory_partition_unit::busy() const { - if (task == SAMPLELOG) { - StatAddSample(cbtol2_Dist, m_icnt2cache_queue->get_length()); - StatAddSample(cbtoL2wr_Dist, m_icnt2cache_write_queue->get_length()); - StatAddSample(L2tocb_Dist, L2tocbqueue->get_length()); - StatAddSample(dramtoL2_Dist, dramtoL2queue->get_length()); - StatAddSample(dramtoL2wr_Dist, dramtoL2writequeue->get_length()); - StatAddSample(L2todram_Dist, L2todramqueue->get_length()); - StatAddSample(L2todram_wb_Dist, L2todram_wbqueue->get_length()); - } else if (task == DUMPLOG) { - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(cbtol2_Dist); - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(cbtoL2wr_Dist); - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2tocb_Dist); - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(dramtoL2_Dist); - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(dramtoL2wr_Dist); - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2todram_Dist); - printf ("Queue Length DRAM[%d] ",m_id); StatDisp(L2todram_wb_Dist); - } + return !m_request_tracker.empty(); } -unsigned memory_partition_unit::flushL2() -{ - return m_L2cache->flush(); -} - -void gpgpu_sim::L2c_latency_log_dump() +void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle ) { - for (unsigned i=0;im_n_mem;i++) - m_memory_partition_unit[i]->L2c_latency_log_dump(); + if (req) { + m_request_tracker.insert(req); + rop_delay_t r; + r.req = req; + r.ready_cycle = cycle + 115; // Add 115*4=460 delay cycles + m_rop.push(r); + req->set_status(IN_PARTITION_ROP_DELAY,gpu_sim_cycle+gpu_tot_sim_cycle); + } + if ( !m_rop.empty() && (cycle >= m_rop.front().ready_cycle) ) { + mem_fetch* mf = m_rop.front().req; + m_rop.pop(); + m_stats->memlatstat_icnt2mem_pop(mf); + m_icnt_L2_queue->push(mf); + mf->set_status(IN_PARTITION_ICNT_TO_L2_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + } } -void memory_partition_unit::L2c_latency_log_dump() +mem_fetch* memory_partition_unit::pop() { - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(m_icnt2cache_queue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(m_icnt2cache_write_queue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2tocbqueue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(dramtoL2queue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(dramtoL2writequeue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2todramqueue->get_lat_stat()); - printf ("(LOGB2)Latency DRAM[%u] ",m_id); StatDisp(L2todram_wbqueue->get_lat_stat()); + mem_fetch* mf = m_L2_icnt_queue->pop(); + if ( mf && mf->isatomic() ) + mf->do_atomic(); + m_request_tracker.erase(mf); + return mf; } -bool memory_partition_unit::busy() const +mem_fetch* memory_partition_unit::top() { - return !m_request_tracker.empty(); + return m_L2_icnt_queue->top(); } +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) { + 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() ) { + mem_fetch *mf = m_L2_dram_queue->pop(); + m_dram->push(mf); + } +} -- cgit v1.3