/* * l2cache.cc * * Copyright (c) 2009 by Tor M. Aamodt and * University of British Columbia * Vancouver, BC V6T 1Z4 * All Rights Reserved. * * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE * TERMS AND CONDITIONS. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda * (property of NVIDIA). The files benchmarks/BlackScholes/ and * benchmarks/template/ are derived from the CUDA SDK available from * http://www.nvidia.com/cuda (also property of NVIDIA). The files from * src/intersim/ are derived from Booksim (a simulator provided with the * textbook "Principles and Practices of Interconnection Networks" available * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by * the corresponding legal terms and conditions set forth separately (original * copyright notices are left in files from these sources and where we have * modified a file our copyright notice appears before the original copyright * notice). * * Using this version of GPGPU-Sim requires a complete installation of CUDA * which is distributed seperately by NVIDIA under separate terms and * conditions. To use this version of GPGPU-Sim with OpenCL requires a * recent version of NVIDIA's drivers which support OpenCL. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the University of British Columbia nor the names of * its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. * * 5. No nonprofit user may place any restrictions on the use of this software, * including as modified by the user, by any other authorized user. * * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, * Ali Bakhoda, George L. Yuan, at the University of British Columbia, * Vancouver, BC V6T 1Z4 */ #include #include #include #include #include #include "../option_parser.h" #include "mem_fetch.h" #include "dram.h" #include "gpu-cache.h" #include "histogram.h" #include "l2cache.h" #include "../intersim/statwraper.h" #include "../abstract_hardware_model.h" #include "gpu-sim.h" #include "shader.h" #include "mem_latency_stat.h" 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_dram = new dram_t(m_id,m_config,m_stats); char L2c_name[32]; snprintf(L2c_name, 32, "L2_bank_%03d", m_id); m_L2interface = new L2interface(this); m_L2cache = new read_only_cache(L2c_name,m_config->m_L2_config,-1,-1,m_L2interface); unsigned int icnt_L2; unsigned int L2_dram; unsigned int dram_L2; unsigned int L2_icnt; 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; } memory_partition_unit::~memory_partition_unit() { 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; } void memory_partition_unit::cache_cycle() { // 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 } } } 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(); } } } bool memory_partition_unit::full() const { return m_icnt_L2_queue->full(); } void memory_partition_unit::print_cache_stat(unsigned &accesses, unsigned &misses) const { 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_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); } 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]->print_cache_stat(k,j); printf("L2 Cache Total Miss Rate = %0.3f\n", (float)j/k); } unsigned memory_partition_unit::flushL2() { m_L2cache->flush(); return 0; // L2 is read only in this version } bool memory_partition_unit::busy() const { return !m_request_tracker.empty(); } void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle ) { 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); } } mem_fetch* memory_partition_unit::pop() { mem_fetch* mf = m_L2_icnt_queue->pop(); if ( mf && mf->isatomic() ) mf->do_atomic(); m_request_tracker.erase(mf); return mf; } mem_fetch* memory_partition_unit::top() { 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); } }