diff options
| author | Tor Aamodt <[email protected]> | 2010-11-28 20:48:33 -0800 |
|---|---|---|
| committer | Tor Aamodt <[email protected]> | 2010-11-28 20:48:33 -0800 |
| commit | 6e06c2e1de8c51a88845b7f35cea219dca7456f2 (patch) | |
| tree | 28b3daed248f3f4dca9ca49f9d939f6edae10238 /src/gpgpu-sim | |
| parent | 23d096dd1f1d4f0387087ffff0605fbf349556d2 (diff) | |
enabling L2 data cache... it is write through, write evict like L1.
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 8154]
Diffstat (limited to 'src/gpgpu-sim')
| -rw-r--r-- | src/gpgpu-sim/dram.cc | 2 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.cc | 18 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-cache.h | 70 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 17 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.h | 1 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.cc | 64 | ||||
| -rw-r--r-- | src/gpgpu-sim/l2cache.h | 22 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.cc | 2 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.h | 27 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 127 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 35 | ||||
| -rw-r--r-- | src/gpgpu-sim/visualizer.cc | 8 |
12 files changed, 310 insertions, 83 deletions
diff --git a/src/gpgpu-sim/dram.cc b/src/gpgpu-sim/dram.cc index 9227310..bd6758b 100644 --- a/src/gpgpu-sim/dram.cc +++ b/src/gpgpu-sim/dram.cc @@ -237,7 +237,7 @@ void dram_t::cycle() if (cmd->dqbytes >= cmd->nbytes) { mem_fetch *data = cmd->data; data->set_status(IN_PARTITION_MC_RETURNQ,gpu_sim_cycle+gpu_tot_sim_cycle); - data->set_type(REPLY_DATA); + data->set_reply(); returnq->push(data); delete cmd; } diff --git a/src/gpgpu-sim/gpu-cache.cc b/src/gpgpu-sim/gpu-cache.cc index 594e683..202511d 100644 --- a/src/gpgpu-sim/gpu-cache.cc +++ b/src/gpgpu-sim/gpu-cache.cc @@ -241,3 +241,21 @@ void tag_array::print( FILE *stream, unsigned &total_access, unsigned &total_mis total_misses+=m_miss; total_access+=m_access; } + +bool was_write_sent( const std::list<cache_event> &events ) +{ + for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) { + if( *e == WRITE_REQUEST_SENT ) + return true; + } + return false; +} + +bool was_read_sent( const std::list<cache_event> &events ) +{ + for( std::list<cache_event>::const_iterator e=events.begin(); e!=events.end(); e++ ) { + if( *e == READ_REQUEST_SENT ) + return true; + } + return false; +} diff --git a/src/gpgpu-sim/gpu-cache.h b/src/gpgpu-sim/gpu-cache.h index 6b93d85..64ebdfa 100644 --- a/src/gpgpu-sim/gpu-cache.h +++ b/src/gpgpu-sim/gpu-cache.h @@ -88,6 +88,12 @@ enum cache_request_status { RESERVATION_FAIL }; +enum cache_event { + WRITE_BACK_REQUEST_SENT, + READ_REQUEST_SENT, + WRITE_REQUEST_SENT +}; + struct cache_block_t { cache_block_t() { @@ -412,22 +418,29 @@ private: class cache_t { public: virtual ~cache_t() {} - virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) = 0; + virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ) = 0; }; +bool was_write_sent( const std::list<cache_event> &events ); +bool was_read_sent( const std::list<cache_event> &events ); + class read_only_cache : public cache_t { public: - read_only_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport ) + read_only_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, + enum mem_fetch_status status ) : m_config(config), m_tag_array(config,core_id,type_id), m_mshrs(config.m_mshr_entries,config.m_mshr_max_merge) { m_name = name; assert(config.m_mshr_type == ASSOC); m_memport=memport; + m_miss_queue_status = status; } // access cache: returns RESERVATION_FAIL if request could not be accepted (for any reason) - virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) { + virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ) + { assert(m_config.m_write_policy == READ_ONLY); + assert(!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); @@ -448,6 +461,8 @@ public: m_extra_mf_fields[mf] = extra_mf_fields(block_addr,cache_index, mf->get_data_size()); mf->set_data_size( m_config.get_line_sz() ); m_miss_queue.push_back(mf); + mf->set_status(m_miss_queue_status,time); + events.push_back(READ_REQUEST_SENT); return MISS; } } @@ -482,6 +497,12 @@ public: m_extra_mf_fields.erase(mf); } + bool waiting_for_fill( mem_fetch *mf ) + { + extra_mf_fields_lookup::iterator e = m_extra_mf_fields.find(mf); + return e != m_extra_mf_fields.end(); + } + // are any (accepted) accesses that had to wait for memory now ready? (does not include accesses that "HIT") bool access_ready() const { @@ -520,6 +541,7 @@ public: tag_array m_tag_array; mshr_table m_mshrs; std::list<mem_fetch*> m_miss_queue; + enum mem_fetch_status m_miss_queue_status; mem_fetch_interface *m_memport; struct extra_mf_fields { @@ -548,12 +570,14 @@ public: class data_cache : public read_only_cache { public: - data_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, mem_fetch_allocator *mfcreator ) - : read_only_cache(name,config,core_id,type_id,memport) + data_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, + mem_fetch_allocator *mfcreator, enum mem_fetch_status status ) + : read_only_cache(name,config,core_id,type_id,memport,status) { m_memfetch_creator=mfcreator; } - virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time ) { + virtual enum cache_request_status access( new_addr_type addr, mem_fetch *mf, unsigned time, std::list<cache_event> &events ) + { bool wr = mf->get_is_write(); enum mem_access_type type = mf->get_access_type(); bool evict = (type == GLOBAL_ACC_W); // evict a line that hits on global memory write @@ -566,19 +590,19 @@ public: if ( m_miss_queue.size() >= m_config.m_miss_queue_size ) return RESERVATION_FAIL; // cannot handle request this cycle - // generate writeback request (this assumes we merge global write with this request) - // this does not ensure coherence since multiple writes to block could occcur at same - // time on different shader cores + // generate a write through cache_block_t &block = m_tag_array.get_block(cache_index); - mem_fetch *wb = m_memfetch_creator->alloc(block_addr,L1_WRBK_ACC,m_config.get_line_sz(),true); - m_miss_queue.push_back(wb); + assert( block.m_status != MODIFIED ); // fails if block was allocated by a ld.local and now accessed by st.global + m_miss_queue.push_back(mf); + mf->set_status(m_miss_queue_status,time); + events.push_back(WRITE_REQUEST_SENT); - // invalidate block + // invalidate block block.m_status = INVALID; } else { m_tag_array.access(block_addr,time,cache_index); // update LRU state if ( wr ) { - assert( type == LOCAL_ACC_W ); + assert( type == LOCAL_ACC_W || /*l2 only*/ type == L1_WRBK_ACC ); // treated as write back... cache_block_t &block = m_tag_array.get_block(cache_index); block.m_status = MODIFIED; @@ -592,6 +616,8 @@ public: // on miss, generate write through (no write buffering -- too many threads for that) m_miss_queue.push_back(mf); + mf->set_status(m_miss_queue_status,time); + events.push_back(WRITE_REQUEST_SENT); return MISS; } else { if ( (m_miss_queue.size()+1) >= m_config.m_miss_queue_size ) @@ -613,11 +639,16 @@ public: m_extra_mf_fields[mf] = extra_mf_fields(block_addr,cache_index, mf->get_data_size()); mf->set_data_size( m_config.get_line_sz() ); m_miss_queue.push_back(mf); + mf->set_status(m_miss_queue_status,time); + events.push_back(READ_REQUEST_SENT); do_miss = true; } if( wb ) { + assert(do_miss); mem_fetch *wb = m_memfetch_creator->alloc(evicted.m_block_addr,L1_WRBK_ACC,m_config.get_line_sz(),true); + events.push_back(WRITE_BACK_REQUEST_SENT); m_miss_queue.push_back(wb); + wb->set_status(m_miss_queue_status,time); } if( do_miss ) return MISS; @@ -637,7 +668,9 @@ public: // http://www-graphics.stanford.edu/papers/texture_prefetch/ class tex_cache : public cache_t { public: - tex_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport ) + tex_cache( const char *name, const cache_config &config, int core_id, int type_id, mem_fetch_interface *memport, + enum mem_fetch_status request_status, + enum mem_fetch_status rob_status ) : m_config(config), m_tags(config,core_id,type_id), m_fragment_fifo(config.m_fragment_fifo_entries), @@ -651,13 +684,15 @@ public: assert(config.m_alloc_policy == ON_MISS); m_memport=memport; m_cache = new data_block[ config.get_num_lines() ]; + m_request_queue_status = request_status; + m_rob_status = rob_status; } // return values: RESERVATION_FAIL if request could not be accepted // 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 access( new_addr_type addr, mem_fetch *mf, unsigned time ) { + enum cache_request_status 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; @@ -675,6 +710,8 @@ public: mf->set_data_size(m_config.get_line_sz()); m_tags.fill(cache_index,time); // mark block as valid m_request_fifo.push(mf); + mf->set_status(m_request_queue_status,time); + events.push_back(READ_REQUEST_SENT); return MISS; } else { // the value *will* *be* in the cache already @@ -726,6 +763,7 @@ public: assert( e != m_extra_mf_fields.end() ); assert( e->second.m_valid ); assert( !m_rob.empty() ); + mf->set_status(m_rob_status,time); unsigned rob_index = e->second.m_rob_index; rob_entry &r = m_rob.peek(rob_index); @@ -884,6 +922,8 @@ public: fifo<mem_fetch*> m_result_fifo; // next completed texture fetch mem_fetch_interface *m_memport; + enum mem_fetch_status m_request_queue_status; + enum mem_fetch_status m_rob_status; struct extra_mf_fields { extra_mf_fields() { m_valid = false;} diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index 359a54d..9bb6a23 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -138,7 +138,10 @@ void memory_config::reg_options(class OptionParser * opp) option_parser_register(opp, "-gpgpu_cache:dl2", OPT_CSTR, &m_L2_config.m_config_string, "unified banked L2 data cache config " " {<nsets>:<bsize>:<assoc>:<rep>:<wr>:<alloc>,<mshr>:<N>:<merge>,<mq>}", - NULL); + NULL); + option_parser_register(opp, "-gpgpu_cache:dl2_texture_only", OPT_BOOL, &m_L2_texure_only, + "L2 cache used for texture only", + "0"); option_parser_register(opp, "-gpgpu_n_mem", OPT_UINT32, &m_n_mem, "number of memory modules (e.g. memory controllers) in gpu", "8"); @@ -518,13 +521,14 @@ unsigned int gpgpu_sim::run_gpu_sim() if( not_completed ) { if ( !num_cores ) { printf("GPGPU-Sim uArch: DEADLOCK shader cores no longer committing instructions [core(# threads)]:\n" ); - printf("GPGPU-Sim uArch: DEADLOCK %u(%u)", i, not_completed); + printf("GPGPU-Sim uArch: DEADLOCK "); + m_cluster[i]->print_not_completed(stdout); } else if (num_cores < 8 ) { - printf(" %u(%u)", i, not_completed); - } else if (num_cores == 8 ) { + m_cluster[i]->print_not_completed(stdout); + } else if (num_cores >= 8 ) { printf(" + others ... "); } - num_cores++; + num_cores+=m_shader_config->n_simt_cores_per_cluster; } } printf("\n"); @@ -868,9 +872,10 @@ void gpgpu_sim::cycle() } } -void shader_core_ctx::dump_istream_state( FILE *fout ) const +void shader_core_ctx::dump_warp_state( FILE *fout ) const { fprintf(fout, "\n"); + fprintf(fout, "per warp functional simulation status:\n"); for (unsigned w=0; w < m_config->max_warps_per_shader; w++ ) m_warp[w].print(fout); } diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index 54b32d0..db0b18f 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -124,6 +124,7 @@ struct memory_config { bool m_valid; cache_config m_L2_config; + bool m_L2_texure_only; char *gpgpu_dram_timing_opt; char *gpgpu_L2_queue_config; diff --git a/src/gpgpu-sim/l2cache.cc b/src/gpgpu-sim/l2cache.cc index ff09d18..bb13cbc 100644 --- a/src/gpgpu-sim/l2cache.cc +++ b/src/gpgpu-sim/l2cache.cc @@ -83,6 +83,21 @@ #include "shader.h" #include "mem_latency_stat.h" + +mem_fetch * partition_mf_allocator::alloc(new_addr_type addr, mem_access_type type, unsigned size, bool wr ) const +{ + assert( wr ); + mem_access_t access( type, addr, size, wr ); + mem_fetch *mf = new mem_fetch( access, + NULL, + WRITE_PACKET_SIZE, + -1, + -1, + -1, + m_memory_config ); + return mf; +} + memory_partition_unit::memory_partition_unit( unsigned partition_id, const struct memory_config *config, class memory_stats_t *stats ) @@ -95,7 +110,8 @@ memory_partition_unit::memory_partition_unit( unsigned partition_id, 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); + m_mf_allocator = new partition_mf_allocator(config); + m_L2cache = new data_cache(L2c_name,m_config->m_L2_config,-1,-1,m_L2interface,m_mf_allocator,IN_PARTITION_L2_MISS_QUEUE); unsigned int icnt_L2; unsigned int L2_dram; @@ -125,14 +141,14 @@ void memory_partition_unit::cache_cycle( unsigned 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_reply(); 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() ) { + if ( m_L2cache->waiting_for_fill(mf) ) { 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(); @@ -149,19 +165,31 @@ void memory_partition_unit::cache_cycle( unsigned 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_config->m_L2_texure_only && mf->istexture()) || (!m_config->m_L2_texure_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); + std::list<cache_event> events; + enum cache_request_status status = m_L2cache->access(mf->get_partition_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle,events); + bool write_sent = was_write_sent(events); + bool read_sent = was_read_sent(events); + if ( status == HIT ) { - // L2 cache replies with data - mf->set_type(REPLY_DATA); - m_L2_icnt_queue->push(mf); - m_icnt_L2_queue->pop(); + if( !write_sent ) { + // L2 cache replies + assert(!read_sent); + mf->set_reply(); + mf->set_status(IN_PARTITION_L2_TO_ICNT_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); + m_L2_icnt_queue->push(mf); + m_icnt_L2_queue->pop(); + } else { + assert(write_sent); + m_icnt_L2_queue->pop(); + } } else if ( status != RESERVATION_FAIL ) { // L2 cache accepted request m_icnt_L2_queue->pop(); } else { + assert(!write_sent); + assert(!read_sent); // L2 cache lock-up: will try again next cycle } } @@ -205,6 +233,7 @@ void memory_partition_unit::print( FILE *fp ) const fprintf(fp," <NULL mem_fetch?>\n"); } } + m_L2cache->display_state(fp); m_dram->print(fp); } @@ -266,15 +295,26 @@ void memory_partition_unit::push( mem_fetch* req, unsigned long long cycle ) mem_fetch* memory_partition_unit::pop() { mem_fetch* mf = m_L2_icnt_queue->pop(); + m_request_tracker.erase(mf); if ( mf && mf->isatomic() ) mf->do_atomic(); - m_request_tracker.erase(mf); + if( mf && (mf->get_access_type() == L2_WRBK_ACC || mf->get_access_type() == L1_WRBK_ACC) ) { + delete mf; + mf = NULL; + } return mf; } mem_fetch* memory_partition_unit::top() { - return m_L2_icnt_queue->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) ) { + m_L2_icnt_queue->pop(); + m_request_tracker.erase(mf); + delete mf; + mf = NULL; + } + return mf; } void memory_partition_unit::dram_cycle() diff --git a/src/gpgpu-sim/l2cache.h b/src/gpgpu-sim/l2cache.h index b7ab49e..761a220 100644 --- a/src/gpgpu-sim/l2cache.h +++ b/src/gpgpu-sim/l2cache.h @@ -74,6 +74,22 @@ class mem_fetch; +class partition_mf_allocator : public mem_fetch_allocator { +public: + partition_mf_allocator( const memory_config *config ) + { + m_memory_config = config; + } + virtual mem_fetch * alloc(const class warp_inst_t &inst, const mem_access_t &access) const + { + abort(); + return NULL; + } + virtual mem_fetch * alloc(new_addr_type addr, mem_access_type type, unsigned size, bool wr) const; +private: + const memory_config *m_memory_config; +}; + class memory_partition_unit { public: @@ -103,8 +119,9 @@ private: unsigned m_id; const struct memory_config *m_config; class dram_t *m_dram; - class read_only_cache *m_L2cache; + class data_cache *m_L2cache; class L2interface *m_L2interface; + partition_mf_allocator *m_mf_allocator; // model delay of ROP units with a fixed latency struct rop_delay_t @@ -140,7 +157,8 @@ public: } virtual void push(mem_fetch *mf) { - m_unit->m_L2_dram_queue->push(mf); + mf->set_status(IN_PARTITION_L2_TO_DRAM_QUEUE,0/*FIXME*/); + m_unit->m_L2_dram_queue->push(mf); } private: memory_partition_unit *m_unit; diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc index f4c3bcc..699ba0a 100644 --- a/src/gpgpu-sim/mem_fetch.cc +++ b/src/gpgpu-sim/mem_fetch.cc @@ -92,7 +92,7 @@ mem_fetch::mem_fetch( const mem_access_t &access, m_wid = wid; config->m_address_mapping.addrdec_tlx(access.get_addr(),&m_raw_addr); m_partition_addr = config->m_address_mapping.partition_address(access.get_addr()); - m_type = m_access.is_write()?WR_REQ:RD_REQ; + m_type = m_access.is_write()?WRITE_REQUEST:READ_REQUEST; m_timestamp = gpu_sim_cycle + gpu_tot_sim_cycle; m_timestamp2 = 0; m_status = MEM_FETCH_INITIALIZED; diff --git a/src/gpgpu-sim/mem_fetch.h b/src/gpgpu-sim/mem_fetch.h index 05e2206..926e51a 100644 --- a/src/gpgpu-sim/mem_fetch.h +++ b/src/gpgpu-sim/mem_fetch.h @@ -72,17 +72,23 @@ #include <bitset> enum mf_type { - RD_REQ = 0, - WR_REQ, - REPLY_DATA // send to shader + READ_REQUEST = 0, + WRITE_REQUEST, + READ_REPLY, // send to shader + WRITE_ACK }; enum mem_fetch_status { MEM_FETCH_INITIALIZED = 0, + IN_L1I_MISS_QUEUE, + IN_L1D_MISS_QUEUE, + IN_L1T_MISS_QUEUE, + IN_L1C_MISS_QUEUE, IN_ICNT_TO_MEM, IN_PARTITION_ROP_DELAY, IN_PARTITION_ICNT_TO_L2_QUEUE, IN_PARTITION_L2_TO_DRAM_QUEUE, + IN_PARTITION_L2_MISS_QUEUE, IN_PARTITION_MC_INTERFACE_QUEUE, IN_PARTITION_MC_INPUT_QUEUE, IN_PARTITION_MC_BANK_ARB_QUEUE, @@ -95,6 +101,7 @@ enum mem_fetch_status { IN_CLUSTER_TO_SHADER_QUEUE, IN_SHADER_LDST_RESPONSE_FIFO, IN_SHADER_FETCHED, + IN_SHADER_L1T_ROB, MEM_FETCH_DELETED, NUM_MEM_REQ_STAT }; @@ -111,7 +118,17 @@ public: ~mem_fetch(); void set_status( enum mem_fetch_status status, unsigned long long cycle ); - void set_type( enum mf_type t ) { m_type=t; } + void set_reply() + { + assert( m_access.get_type() != L1_WRBK_ACC && m_access.get_type() != L2_WRBK_ACC ); + if( m_type==READ_REQUEST ) { + assert( !get_is_write() ); + m_type = READ_REPLY; + } else if( m_type == WRITE_REQUEST ) { + assert( get_is_write() ); + m_type = WRITE_ACK; + } + } void do_atomic(); void print( FILE *fp, bool print_inst = true ) const; @@ -152,7 +169,7 @@ private: unsigned m_wid; // where is this request now? - enum mem_fetch_status m_status; + enum mem_fetch_status m_status; unsigned long long m_status_change; // request type, address, size, mask diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 303d736..e9ec368 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -127,6 +127,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader); m_not_completed = 0; + m_active_threads.reset(); m_n_active_cta = 0; for (unsigned i = 0; i<MAX_CTA_PER_SHADER; i++ ) m_cta_status[i]=0; @@ -145,7 +146,7 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, #define STRSIZE 1024 char name[STRSIZE]; snprintf(name, STRSIZE, "L1I_%03d", m_sid); - m_L1I = new read_only_cache( name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id(),m_icnt); + m_L1I = new read_only_cache( name,m_config->m_L1I_config,m_sid,get_shader_instruction_cache_id(),m_icnt,IN_L1I_MISS_QUEUE); m_warp.resize(m_config->max_warps_per_shader, shd_warp_t(this, warp_size)); m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; @@ -183,12 +184,17 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_fu[2] = m_ldst_unit; m_dispatch_port[2] = ID_OC_MEM; m_issue_port[2] = OC_EX_MEM; + + m_last_inst_gpu_sim_cycle = 0; + m_last_inst_gpu_tot_sim_cycle = 0; } void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed ) { - if( reset_not_completed ) + if( reset_not_completed ) { m_not_completed = 0; + m_active_threads.reset(); + } for (unsigned i = start_thread; i<end_thread; i++) { m_thread[i].n_insn = 0; m_thread[i].m_cta_id = -1; @@ -208,14 +214,19 @@ void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsign for (unsigned i = start_warp; i < end_warp; ++i) { unsigned initial_active_mask = 0; unsigned n_active=0; + std::bitset<MAX_WARP_SIZE> active_threads; for (unsigned t = 0; t < m_config->warp_size; t++) { - if ( i * m_config->warp_size + t < end_thread ) { + unsigned hwtid = i * m_config->warp_size + t; + if ( hwtid < end_thread ) { initial_active_mask |= (1 << t); n_active++; + assert( !m_active_threads.test(hwtid) ); + m_active_threads.set( hwtid ); + active_threads.set(t); } } m_pdom_warp[i]->launch(start_pc,initial_active_mask); - m_warp[i].init(start_pc,cta_id,i,n_active); + m_warp[i].init(start_pc,cta_id,i,active_threads); m_not_completed += n_active; } } @@ -509,14 +520,16 @@ void shader_core_ctx::fetch() // and get next 1-2 instructions from i-cache... for( unsigned i=0; i < m_config->max_warps_per_shader; i++ ) { unsigned warp_id = (m_last_warp_fetched+1+i) % m_config->max_warps_per_shader; - if( m_warp[warp_id].done() && !m_scoreboard->pendingWrites(warp_id) && !m_warp[warp_id].done_exit() - && m_warp[warp_id].stores_done() && !m_warp[warp_id].inst_in_pipeline() ) { + + // this code checks if this warp has finished executing and can be reclaimed + if( m_warp[warp_id].hardware_done() && !m_scoreboard->pendingWrites(warp_id) && !m_warp[warp_id].done_exit() ) { bool did_exit=false; for( unsigned t=0; t<m_config->warp_size;t++) { unsigned tid=warp_id*m_config->warp_size+t; if( m_thread[tid].m_functional_model_thread_state ) { register_cta_thread_exit(tid); m_not_completed -= 1; + m_active_threads.reset(tid); m_thread[tid].m_functional_model_thread_state=NULL; did_exit=true; } @@ -524,7 +537,9 @@ void shader_core_ctx::fetch() if( did_exit ) m_warp[warp_id].set_done_exit(); } - if( !m_warp[warp_id].done() && !m_warp[warp_id].imiss_pending() && m_warp[warp_id].ibuffer_empty() ) { + + // this code fetches instructions from the i-cache or generates memory requests + if( !m_warp[warp_id].functional_done() && !m_warp[warp_id].imiss_pending() && m_warp[warp_id].ibuffer_empty() ) { address_type pc = m_warp[warp_id].get_pc(); address_type ppc = pc + PROGRAM_MEM_START; unsigned nbytes=16; @@ -542,7 +557,8 @@ void shader_core_ctx::fetch() m_sid, m_tpc, m_memory_config ); - enum cache_request_status status = m_L1I->access( (new_addr_type)ppc, mf, gpu_sim_cycle+gpu_tot_sim_cycle ); + std::list<cache_event> events; + enum cache_request_status status = m_L1I->access( (new_addr_type)ppc, mf, gpu_sim_cycle+gpu_tot_sim_cycle,events); if( status == MISS ) { m_last_warp_fetched=warp_id; m_warp[warp_id].set_imiss_pending(); @@ -551,6 +567,7 @@ void shader_core_ctx::fetch() m_last_warp_fetched=warp_id; m_inst_fetch_buffer = ifetch_buffer_t(pc,nbytes,warp_id); m_warp[warp_id].set_last_fetch(gpu_sim_cycle); + delete mf; } else { assert( status == RESERVATION_FAIL ); delete mf; @@ -581,7 +598,7 @@ void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) inst.set_addr(t, translate_local_memaddr(inst.get_addr(t), tid, m_config->n_simt_clusters*m_config->n_simt_cores_per_cluster) ); if ( ptx_thread_done(tid) ) { - m_warp[inst.warp_id()].inc_n_completed(); + m_warp[inst.warp_id()].set_completed(t); m_warp[inst.warp_id()].ibuffer_flush(); } } @@ -748,6 +765,8 @@ void shader_core_ctx::writeback() m_stats->m_num_sim_insn[m_sid]++; m_gpu->gpu_sim_insn_last_update_sid = m_sid; m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle; + m_last_inst_gpu_sim_cycle = gpu_sim_cycle; + m_last_inst_gpu_tot_sim_cycle = gpu_tot_sim_cycle; m_gpu->gpu_sim_insn += pipe_reg->active_count(); pipe_reg->clear(); } @@ -775,24 +794,32 @@ mem_stage_stall_type ldst_unit::process_memory_access_queue( cache_t *cache, war const mem_access_t &access = inst.accessq_back(); mem_fetch *mf = m_mf_allocator->alloc(inst,inst.accessq_back()); - enum cache_request_status status = cache->access(mf->get_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle); + std::list<cache_event> events; + enum cache_request_status status = cache->access(mf->get_addr(),mf,gpu_sim_cycle+gpu_tot_sim_cycle,events); + bool write_sent = was_write_sent(events); + bool read_sent = was_read_sent(events); + if( write_sent ) + m_core->inc_store_req( inst.warp_id() ); if ( status == HIT ) { + assert( !read_sent ); inst.accessq_pop_back(); - delete mf; + if( !write_sent ) + delete mf; } else if ( status == RESERVATION_FAIL ) { result = COAL_STALL; + assert( !read_sent ); + assert( !write_sent ); delete mf; } else { - inst.clear_active( access.get_warp_mask() ); // threads in mf writeback when mf returns assert( status == MISS || status == HIT_RESERVED ); + inst.clear_active( access.get_warp_mask() ); // threads in mf writeback when mf returns inst.accessq_pop_back(); if ( inst.is_load() ) { for ( unsigned r=0; r < 4; r++) if (inst.out[r] > 0) m_pending_writes[inst.warp_id()][inst.out[r]]++; - } else if( inst.is_store() ) - m_core->inc_store_req( inst.warp_id() ); + } } if( !inst.accessq_empty() ) result = BK_CONF; @@ -951,15 +978,17 @@ ldst_unit::ldst_unit( shader_memory_interface *icnt, snprintf(L1T_name, STRSIZE, "L1T_%03d", m_sid); snprintf(L1C_name, STRSIZE, "L1C_%03d", m_sid); snprintf(L1D_name, STRSIZE, "L1D_%03d", m_sid); - m_L1T = new tex_cache(L1T_name,m_config->m_L1T_config,m_sid,get_shader_texture_cache_id(),icnt); - m_L1C = new read_only_cache(L1C_name,m_config->m_L1C_config,m_sid,get_shader_constant_cache_id(),icnt); + m_L1T = new tex_cache(L1T_name,m_config->m_L1T_config,m_sid,get_shader_texture_cache_id(),icnt,IN_L1T_MISS_QUEUE,IN_SHADER_L1T_ROB); + m_L1C = new read_only_cache(L1C_name,m_config->m_L1C_config,m_sid,get_shader_constant_cache_id(),icnt,IN_L1C_MISS_QUEUE); m_L1D = NULL; if( !m_config->m_L1D_config.disabled() ) - m_L1D = new data_cache(L1D_name,m_config->m_L1D_config,m_sid,get_shader_normal_cache_id(),m_icnt,m_mf_allocator); + m_L1D = new data_cache(L1D_name,m_config->m_L1D_config,m_sid,get_shader_normal_cache_id(),m_icnt,m_mf_allocator,IN_L1D_MISS_QUEUE); m_mem_rc = NO_RC_FAIL; m_num_writeback_clients=5; // = shared memory, global/local (uncached), L1D, L1T, L1C m_writeback_arb = 0; m_next_global=NULL; + m_last_inst_gpu_sim_cycle=0; + m_last_inst_gpu_tot_sim_cycle=0; } void ldst_unit::writeback() @@ -984,6 +1013,8 @@ void ldst_unit::writeback() } } m_next_wb.clear(); + m_last_inst_gpu_sim_cycle = gpu_sim_cycle; + m_last_inst_gpu_tot_sim_cycle = gpu_tot_sim_cycle; } } @@ -1046,7 +1077,6 @@ void ldst_unit::cycle() if( !m_response_fifo.empty() ) { mem_fetch *mf = m_response_fifo.front(); if (mf->istexture()) { - mf->set_status(IN_SHADER_FETCHED,gpu_sim_cycle+gpu_tot_sim_cycle); m_L1T->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); m_response_fifo.pop_front(); } else if (mf->isconst()) { @@ -1054,11 +1084,12 @@ void ldst_unit::cycle() m_L1C->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); m_response_fifo.pop_front(); } else { - if( mf->get_is_write() ) { + if( mf->get_type() == WRITE_ACK ) { m_core->store_ack(mf); m_response_fifo.pop_front(); delete mf; } else { + assert( !mf->get_is_write() ); // L1 cache is write evict, allocate line on load miss only if( mf->get_inst().cache_op != CACHE_GLOBAL && m_L1D ) { m_L1D->fill(mf,gpu_sim_cycle+gpu_tot_sim_cycle); m_response_fifo.pop_front(); @@ -1247,10 +1278,10 @@ void shader_core_ctx::print_stage(unsigned int stage, FILE *fout ) const m_pipeline_reg[stage]->print(fout); } -void shader_core_ctx::display_pdom_state(FILE *fout, int mask ) const +void shader_core_ctx::display_simt_state(FILE *fout, int mask ) const { if ( (mask & 4) && m_config->model == POST_DOMINATOR ) { - fprintf(fout,"warp status:\n"); + fprintf(fout,"per warp SIMT control-flow state:\n"); unsigned n = m_config->n_thread_per_shader / m_config->warp_size; for (unsigned i=0; i < n; i++) { unsigned nactive = 0; @@ -1294,6 +1325,8 @@ void ldst_unit::print(FILE *fout) const } fprintf(fout,"LD/ST wb = "); m_next_wb.print(fout); + fprintf(fout, "Last LD/ST writeback @ %llu + %llu (gpu_sim_cycle+gpu_tot_sim_cycle)\n", + m_last_inst_gpu_sim_cycle, m_last_inst_gpu_tot_sim_cycle ); fprintf(fout,"Pending register writes:\n"); std::map<unsigned/*warp_id*/, std::map<unsigned/*regnum*/,unsigned/*count*/> >::const_iterator w; for( w=m_pending_writes.begin(); w!=m_pending_writes.end(); w++ ) { @@ -1325,7 +1358,7 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) con gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed); fprintf(fout, "=================================================\n"); - dump_istream_state(fout); + dump_warp_state(fout); fprintf(fout,"\n"); m_L1I->display_state(fout); @@ -1345,7 +1378,7 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) con m_warp[i].print_ibuffer(fout); } fprintf(fout,"\n"); - display_pdom_state(fout,mask); + display_simt_state(fout,mask); m_scoreboard->printContents(); @@ -1371,6 +1404,24 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) con fprintf(fout, "EX/WB = "); print_stage(EX_WB, fout); fprintf(fout, "\n"); + fprintf(fout, "Last EX/WB writeback @ %llu + %llu (gpu_sim_cycle+gpu_tot_sim_cycle)\n", + m_last_inst_gpu_sim_cycle, m_last_inst_gpu_tot_sim_cycle ); + + if( m_active_threads.count() <= 2*m_config->warp_size ) { + fprintf(fout,"Active Threads : "); + unsigned last_warp_id = -1; + for(unsigned tid=0; tid < m_active_threads.size(); tid++ ) { + unsigned warp_id = tid/m_config->warp_size; + if( m_active_threads.test(tid) ) { + if( warp_id != last_warp_id ) { + fprintf(fout,"\n warp %u : ", warp_id ); + last_warp_id=warp_id; + } + fprintf(fout,"%u ", tid ); + } + } + } + } unsigned int shader_core_config::max_cta( const kernel_info_t &k ) const @@ -1679,18 +1730,24 @@ void shader_core_ctx::accept_ldst_unit_response(mem_fetch * mf) void shader_core_ctx::store_ack( class mem_fetch *mf ) { + assert( mf->get_type() == WRITE_ACK ); unsigned warp_id = mf->get_wid(); m_warp[warp_id].dec_store_req(); } -bool shd_warp_t::done() +bool shd_warp_t::functional_done() const { return get_n_completed() == m_warp_size; } +bool shd_warp_t::hardware_done() const +{ + return functional_done() && stores_done() && !inst_in_pipeline(); +} + bool shd_warp_t::waiting() { - if ( done() ) { + if ( functional_done() ) { // waiting to be initialized with a kernel return true; } else if ( m_shader->warp_waiting_at_barrier(m_warp_id) ) { @@ -1712,10 +1769,14 @@ bool shd_warp_t::waiting() void shd_warp_t::print( FILE *fout ) const { - if ( n_completed < m_warp_size ) { - fprintf( fout, "w%02u npc: 0x%04x, done:%2u i:%u s:%u a:%u (done: ", + if( !done_exit() ) { + fprintf( fout, "w%02u npc: 0x%04x, done:%c%c%c%c:%2u i:%u s:%u a:%u (done: ", m_warp_id, m_next_pc, + (functional_done()?'f':' '), + (stores_done()?'s':' '), + (inst_in_pipeline()?' ':'i'), + (done_exit()?'e':' '), n_completed, m_inst_in_pipeline, m_stores_outstanding, @@ -1727,6 +1788,7 @@ void shd_warp_t::print( FILE *fout ) const fprintf(fout,","); } fprintf(fout,") "); + fprintf(fout," active=%s", m_active_threads.to_string().c_str() ); fprintf(fout," last fetched @ %5llu", m_last_fetch); if( m_imiss_pending ) fprintf(fout," i-miss pending"); @@ -2023,6 +2085,15 @@ unsigned simt_core_cluster::get_not_completed() const return not_completed; } +void simt_core_cluster::print_not_completed( FILE *fp ) const +{ + for( unsigned i=0; i < m_config->n_simt_cores_per_cluster; i++ ) { + unsigned not_completed=m_core[i]->get_not_completed(); + unsigned sid=m_config->cid_to_sid(i,m_cluster_id); + fprintf(fp,"%u(%u) ", sid, not_completed ); + } +} + unsigned simt_core_cluster::get_n_active_cta() const { unsigned n=0; @@ -2109,7 +2180,7 @@ void simt_core_cluster::icnt_cycle() if (!mf) return; assert(mf->get_tpc() == m_cluster_id); - assert(mf->get_type() == REPLY_DATA); + assert(mf->get_type() == READ_REPLY || mf->get_type() == WRITE_ACK ); mf->set_status(IN_CLUSTER_TO_SHADER_QUEUE,gpu_sim_cycle+gpu_tot_sim_cycle); //m_memory_stats->memlatstat_read_done(mf,m_shader_config->max_warps_per_shader); m_response_fifo.push_back(mf); diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index bfe0cc2..17dbd9e 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -140,22 +140,25 @@ public: n_completed = m_warp_size; m_n_atomic=0; m_membar=false; - m_done_exit=false; + m_done_exit=true; m_last_fetch=0; m_next=0; } - void init( address_type start_pc, unsigned cta_id, unsigned wid, unsigned active ) + void init( address_type start_pc, unsigned cta_id, unsigned wid, const std::bitset<MAX_WARP_SIZE> &active ) { m_cta_id=cta_id; m_warp_id=wid; m_next_pc=start_pc; - assert( n_completed >= active ); + assert( n_completed >= active.count() ); assert( n_completed <= m_warp_size); - n_completed -= active; // active threads are not yet completed + n_completed -= active.count(); // active threads are not yet completed + m_active_threads = active; + m_done_exit=false; } - bool done(); - bool waiting(); + bool functional_done() const; + bool waiting(); // not const due to membar + bool hardware_done() const; bool done_exit() const { return m_done_exit; } void set_done_exit() { m_done_exit=true; } @@ -164,7 +167,12 @@ public: void print_ibuffer( FILE *fout ) const; unsigned get_n_completed() const { return n_completed; } - void inc_n_completed() { n_completed++; } + void set_completed( unsigned lane ) + { + assert( m_active_threads.test(lane) ); + m_active_threads.reset(lane); + n_completed++; + } void set_last_fetch( unsigned long long sim_cycle ) { m_last_fetch=sim_cycle; } @@ -241,6 +249,7 @@ private: address_type m_next_pc; unsigned n_completed; // number of threads in warp completed + std::bitset<MAX_WARP_SIZE> m_active_threads; bool m_imiss_pending; @@ -901,6 +910,10 @@ private: enum mem_stage_stall_type m_mem_rc; shader_core_stats *m_stats; + + // for debugging + unsigned long long m_last_inst_gpu_sim_cycle; + unsigned long long m_last_inst_gpu_tot_sim_cycle; }; enum pipeline_stage_name_t { @@ -1136,7 +1149,7 @@ public: const shader_core_config *get_config() const { return m_config; } // debug: - void display_pdom_state(FILE *fout, int mask ) const; + void display_simt_state(FILE *fout, int mask ) const; void display_pipeline( FILE *fout, int print_mem, int mask3bit ) const; private: @@ -1157,8 +1170,10 @@ private: void writeback(); // used in display_pipeline(): - void dump_istream_state( FILE *fout ) const; + void dump_warp_state( FILE *fout ) const; void print_stage(unsigned int stage, FILE *fout) const; + unsigned long long m_last_inst_gpu_sim_cycle; + unsigned long long m_last_inst_gpu_tot_sim_cycle; // general information unsigned m_sid; // shader id @@ -1175,6 +1190,7 @@ private: unsigned m_n_active_cta; // number of Cooperative Thread Arrays (blocks) currently running on this shader. unsigned m_cta_status[MAX_CTA_PER_SHADER]; // CTAs status unsigned m_not_completed; // number of threads to be completed (==0 when all thread on this core completed) + std::bitset<MAX_THREAD_PER_SM> m_active_threads; // thread contexts thread_ctx_t *m_thread; // functional state, per thread fetch state @@ -1228,6 +1244,7 @@ public: void get_pdom_stack_top_info( unsigned sid, unsigned tid, unsigned *pc, unsigned *rpc ) const; unsigned max_cta( const kernel_info_t &kernel ); unsigned get_not_completed() const; + void print_not_completed( FILE *fp ) const; unsigned get_n_active_cta() const; gpgpu_sim *get_gpu() { return m_gpu; } diff --git a/src/gpgpu-sim/visualizer.cc b/src/gpgpu-sim/visualizer.cc index c2b1d16..1c32692 100644 --- a/src/gpgpu-sim/visualizer.cc +++ b/src/gpgpu-sim/visualizer.cc @@ -394,9 +394,9 @@ void time_vector_print_interval2gzfile(gzFile outfile) { #include "../gpgpu-sim/mem_fetch.h" void time_vector_update(unsigned int uid,int slot ,long int cycle,int type) { - if ( (type == RD_REQ) || (type == REPLY_DATA) ) { + if ( (type == READ_REQUEST) || (type == READ_REPLY) ) { g_my_time_vector->update_ld( uid, slot,cycle); - } else if ( type == WR_REQ ) { + } else if ( (type == WRITE_REQUEST) || (type == WRITE_ACK) ) { g_my_time_vector->update_st( uid, slot,cycle); } else { abort(); @@ -405,9 +405,9 @@ void time_vector_update(unsigned int uid,int slot ,long int cycle,int type) { void check_time_vector_update(unsigned int uid,int slot ,long int latency,int type) { - if ( (type == RD_REQ) || (type == REPLY_DATA) ) { + if ( (type == READ_REQUEST) || (type == READ_REPLY) ) { g_my_time_vector->check_ld_update( uid, slot, latency ); - } else if ( type == WR_REQ ) { + } else if ( (type == WRITE_REQUEST) || (type == WRITE_ACK) ) { g_my_time_vector->check_st_update( uid, slot, latency ); } else { abort(); |
