From 4fce546cc9778b889bd07cf852be29b70a44f47d Mon Sep 17 00:00:00 2001 From: Tor Aamodt Date: Sat, 9 Oct 2010 07:58:44 -0800 Subject: Refactoring: 1. Moving mem_access_t to abstract_hardware_model and making set (queue) of accesses part of warp_inst_t. I.e., treat set of accesses as an ISA concept rather than a hardware organization concept. This is only partly "done"... logic for computing accesses is still part of shader_core_ctx in this CL. Given number of warp_inst_t accessors for accessq, now seems like we might even want to move some memory stage code into warp_inst_t class. How those accesses make it to memory system is the hardware concept. 2. Making warp_inst_t an explicit arguement of subroutines used in memory stage... The eventual goal here is (likely) to refactor memory into a hardware block... i.e., have function units be a class that contains some set of pipeline stages internally and some set of input/output "ports". 3. Moving accessor functions is_load, is_store; is_const, is_local into class declaration (where they belong). 4. Removing code for selecting pipeline uarch (might add it back later, but first want a clean GT200 organization). In particular, removing option to have an operand collector -- now you MUST have the operand collector. 5. Removing more deadcode from prior changes (fixed delay queue related) Scripts/configs: 6. Correlation script not printing out exit condition when hardware launch fails 7. Update config files to have proper compute model selected [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7834] --- src/abstract_hardware_model.cc | 8 + src/abstract_hardware_model.h | 75 +++++++ src/cuda-sim/cuda-sim.cc | 16 +- src/debug.cc | 5 +- src/gpgpu-sim/gpu-sim.cc | 21 +- src/gpgpu-sim/gpu-sim.h | 4 +- src/gpgpu-sim/shader.cc | 496 ++++++++++++++++++----------------------- src/gpgpu-sim/shader.h | 170 +++----------- 8 files changed, 338 insertions(+), 457 deletions(-) (limited to 'src') diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index a0e21f7..c52be1d 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -1,5 +1,8 @@ #include "abstract_hardware_model.h" #include "cuda-sim/memory.h" +#include + +unsigned mem_access_t::next_access_uid = 0; void move_warp( warp_inst_t *&dst, warp_inst_t *&src ) { @@ -19,3 +22,8 @@ gpgpu_t::gpgpu_t() g_dev_malloc=GLOBAL_HEAP_START; } + +void warp_inst_t::sort_accessq( unsigned qbegin ) +{ + std::stable_sort( m_accessq.begin()+qbegin,m_accessq.end()); +} diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index c90d56e..7162441 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -223,11 +223,68 @@ public: enum _memory_space_t get_type() const { return m_type; } unsigned get_bank() const { return m_bank; } void set_bank( unsigned b ) { m_bank = b; } + bool is_const() const { return (m_type == const_space) || (m_type == param_space_kernel); } + bool is_local() const { return (m_type == local_space) || (m_type == param_space_local); } + private: enum _memory_space_t m_type; unsigned m_bank; // n in ".const[n]"; note .const == .const[0] (see PTX 2.1 manual, sec. 5.1.3) }; +class mem_access_t { +public: + mem_access_t() + { + init(); + } + mem_access_t(address_type address, unsigned size, unsigned quarter, unsigned idx ) + { + init(); + addr = address; + req_size = size; + quarter_count[quarter]++; + warp_indices.push_back(idx); + } + + bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse + +private: + void init() + { + uid=++next_access_uid; + addr=0; + req_size=0; + order=0; + _quarter_count_all=0; + cache_hit = false; + cache_checked = false; + recheck_cache = false; + need_wb = false; + wb_addr = 0; + reserved_mshr = NULL; + } + +public: + + unsigned uid; + address_type addr; //address of the segment to load. + unsigned req_size; //bytes + unsigned order; // order of accesses, based on banks. + union{ + unsigned _quarter_count_all; + char quarter_count[4]; //access counts to each quarter of segment, for compaction; + }; + std::vector warp_indices; // warp indicies for this request. + bool cache_hit; + bool cache_checked; + bool recheck_cache; + bool need_wb; + address_type wb_addr; // writeback address (if necessary). + class mshr_entry* reserved_mshr; + +private: + static unsigned next_access_uid; +}; #define MAX_REG_OPERANDS 8 @@ -260,6 +317,8 @@ public: { fprintf(fp," [inst @ pc=0x%04x] ", pc ); } + bool is_load() const { return (op == LOAD_OP || memory_op == memory_load); } + bool is_store() const { return (op == STORE_OP || memory_op == memory_store); } address_type pc; // program counter address of instruction unsigned isize; // size of instruction in bytes @@ -362,6 +421,10 @@ public: } } } + void set_not_active( unsigned lane_id ) + { + warp_active_mask.reset(lane_id); + } // accessors virtual void print_insn(FILE *fp) const @@ -391,6 +454,16 @@ public: bool isatomic() const { return m_isatomic; } + bool mem_accesses_computed() const { return m_mem_accesses_created; } + void set_mem_accesses_computed() { m_mem_accesses_created=true; } + bool accessq_empty() const { return m_accessq.empty(); } + unsigned get_accessq_size() const { return m_accessq.size(); } + mem_access_t &accessq( unsigned n ) { return m_accessq[n]; } + mem_access_t &accessq_back() { return m_accessq.back(); } + void accessq_push_back( const mem_access_t &req ) { m_accessq.push_back(req); } + void accessq_pop_back() { m_accessq.pop_back(); } + void sort_accessq( unsigned qbegin ); + protected: bool m_empty; unsigned long long issue_cycle; @@ -410,6 +483,8 @@ protected: }; bool m_per_scalar_thread_valid; std::vector m_per_scalar_thread; + bool m_mem_accesses_created; + std::vector m_accessq; }; void move_warp( warp_inst_t *&dst, warp_inst_t *&src ); diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index 7f4eebd..5293d7d 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -873,21 +873,20 @@ void ptx_thread_info::ptx_exec_inst( warp_inst_t &inst, unsigned lane_id ) skip = !pred_lookup(pI->get_pred_mod(), pred_value.pred & 0x000F); } } - if( !skip ) { + if( skip ) { + inst.set_not_active(lane_id); + } else { ptx_instruction *pJ = NULL; if( pI->get_opcode() == VOTE_OP ) { pJ = new ptx_instruction(*pI); - *((warp_inst_t*)pJ) = inst; + *((warp_inst_t*)pJ) = inst; // copy active mask information pI = pJ; } switch ( pI->get_opcode() ) { #define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,this); op_classification = CLASSIFICATION; break; #include "opcodes.def" #undef OP_DEF - - default: - printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() ); - break; + default: printf( "Execution error: Invalid opcode (0x%x)\n", pI->get_opcode() ); break; } delete pJ; @@ -1024,10 +1023,7 @@ void ptx_thread_info::ptx_exec_inst( warp_inst_t &inst, unsigned lane_id ) inst.set_addr(lane_id, insn_memaddr); inst.data_size = insn_data_size; inst.memory_op = insn_memory_op; - } else { - inst.space = undefined_space; - inst.memory_op = no_memory_op; - } + } } catch ( int x ) { printf("GPGPU-Sim PTX: ERROR (%d) executing intruction (%s:%u)\n", x, pI->source_file(), pI->source_line() ); diff --git a/src/debug.cc b/src/debug.cc index c1aa3c6..928c057 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -85,9 +85,8 @@ void gpgpu_sim::gpgpu_debug() } } else { for( unsigned sid=0; sid < m_n_shader; sid++ ) { - unsigned hw_thread_id = m_sc[sid]->first_valid_thread(IF_ID); - if( hw_thread_id == (unsigned)-1 ) - continue; + unsigned hw_thread_id = -1; + abort(); ptx_thread_info *thread = m_sc[sid]->get_functional_thread(hw_thread_id); if( thread_at_brkpt(thread, b) ) { done = false; diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index 77c6aae..7646ee7 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -221,10 +221,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) "enable perfect memory mode (no cache miss)", "0"); - option_parser_register(opp, "-gpgpu_sm_uarch", OPT_CSTR, &m_shader_config->pipeline_model, - "shader core uarch model [GPGPUSIM_ORIG,GT200] (default=GPGPUSIM_ORIG)", - "GPGPUSIM_ORIG"); - option_parser_register(opp, "-gpgpu_shader_core_pipeline", OPT_CSTR, &gpgpu_shader_core_pipeline_opt, "shader core pipeline config, i.e., {::}", "256:32:32"); @@ -378,9 +374,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) &m_ptx_force_max_capability, "Force maximum compute capability", "0"); - option_parser_register(opp, "-gpgpu_operand_collector", OPT_BOOL, &m_shader_config->gpgpu_operand_collector, - "Enable operand collector model (default = off)", - "0"); option_parser_register(opp, "-gpgpu_operand_collector_num_units", OPT_INT32, &m_shader_config->gpgpu_operand_collector_num_units, "number of collecture units (default = 4)", "4"); @@ -914,12 +907,10 @@ unsigned gpgpu_sim::threads_per_core() const return m_shader_config->n_thread_per_shader; } -void gpgpu_sim::mem_instruction_stats(warp_inst_t* warp) +void gpgpu_sim::mem_instruction_stats(warp_inst_t &inst) { - if( warp->empty() ) - return; //bubble //this breaks some encapsulation: the is_[space] functions, if you change those, change this. - switch (warp->space.get_type()) { + switch (inst.space.get_type()) { case undefined_space: case reg_space: break; @@ -938,7 +929,7 @@ void gpgpu_sim::mem_instruction_stats(warp_inst_t* warp) break; case global_space: case local_space: - if( is_store(*warp) ) + if( inst.is_store() ) m_shader_stats->gpgpu_n_store_insn++; else m_shader_stats->gpgpu_n_load_insn++; @@ -1009,10 +1000,8 @@ void shader_core_ctx::fill_shd_L1_with_new_line(mem_fetch * mf) void shader_core_ctx::store_ack( class mem_fetch *mf ) { - if (!strcmp("GT200",m_config->pipeline_model) ) { unsigned warp_id = mf->get_wid(); m_warp[warp_id].dec_store_req(); - } } void gpgpu_sim::fq_pop(int tpc_id) @@ -1290,9 +1279,7 @@ void gpgpu_sim::cycle() // L1 cache + shader core pipeline stages for (unsigned i=0;iget_not_completed() || more_thread) { - if (!strcmp("GT200",m_shader_config->pipeline_model) ) m_sc[i]->cycle_gt200(); - else abort(); } } if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) { @@ -1426,8 +1413,6 @@ void gpgpu_sim::dump_pipeline( int mask, int s, int m ) const i = s; } if(mask&1) m_sc[i]->display_pipeline(stdout, 1, mask & 0x2E ); - if (!strcmp("GPGPUSIM_ORIG",m_shader_config->pipeline_model) ) - if(mask&0x40) m_sc[i]->dump_istream_state(stdout); if(mask&0x100) m_sc[i]->mshr_print(stdout, mask); if(s != -1) { break; diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index a41849e..37c87f4 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -103,7 +103,6 @@ enum divergence_support_t { struct shader_core_config { - char *pipeline_model; unsigned warp_size; bool gpgpu_perfect_mem; enum divergence_support_t model; @@ -118,7 +117,6 @@ struct shader_core_config char *gpgpu_cache_il1_opt; unsigned n_mshr_per_shader; bool gpgpu_dwf_reg_bankconflict; - bool gpgpu_operand_collector; int gpgpu_operand_collector_num_units; int gpgpu_operand_collector_num_units_sfu; bool gpgpu_stall_on_use; @@ -205,7 +203,7 @@ public: unsigned num_shader() const { return m_n_shader; } unsigned threads_per_core() const; - void mem_instruction_stats( class warp_inst_t* warp); + void mem_instruction_stats( class warp_inst_t &inst); int issue_mf_from_fq(class mem_fetch *mf); void gpu_print_stat() const; diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 1d51004..9ffb3e7 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -1,5 +1,5 @@ /* - * shader.c + * shader.cc * * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda, * George L. Yuan, Ivan Sham, Henry Wong, Dan O'Connor, Henry Tran and the @@ -86,8 +86,6 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) -unsigned mem_access_t::next_access_uid = 0; - ///////////////////////////////////////////////////////////////////////////// /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ @@ -306,12 +304,6 @@ unsigned char shader_core_ctx::fq_push(unsigned long long int addr, return(m_gpu->issue_mf_from_fq(mf)); } -unsigned shader_core_ctx::first_valid_thread( unsigned stage ) -{ - abort(); -} - - void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const { m_L1D->shd_cache_print(fp,total_accesses,total_misses); @@ -401,24 +393,16 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; for (unsigned i = 0; i < config->max_warps_per_shader; ++i) m_pdom_warp[i] = new pdom_warp_ctx_t(i,this); - m_shader_memory_new_instruction_processed = false; m_mem_rc = NO_RC_FAIL, // Initialize scoreboard m_scoreboard = new Scoreboard(m_sid, m_config->max_warps_per_shader); - if( m_config->gpgpu_operand_collector ) { - m_operand_collector.init( m_config->gpgpu_operand_collector_num_units, - m_config->gpgpu_operand_collector_num_units_sfu, - m_config->gpgpu_num_reg_banks, this, - &m_pipeline_reg[ID_EX], - &m_pipeline_reg[OC_EX_SFU] ); - } - - m_memory_queue.shared.reserve(warp_size); - m_memory_queue.constant.reserve(warp_size); - m_memory_queue.texture.reserve(warp_size); - m_memory_queue.local_global.reserve(warp_size); + m_operand_collector.init( m_config->gpgpu_operand_collector_num_units, + m_config->gpgpu_operand_collector_num_units_sfu, + m_config->gpgpu_num_reg_banks, this, + &m_pipeline_reg[OC_EX_SP], + &m_pipeline_reg[OC_EX_SFU] ); // fetch m_last_warp_fetched = 0; @@ -701,27 +685,6 @@ void shader_core_ctx::fetch_new() } } -int is_load ( const inst_t &inst ) -{ - return (inst.op == LOAD_OP || inst.memory_op == memory_load); -} - -int is_store ( const inst_t &inst ) -{ - return (inst.op == STORE_OP || inst.memory_op == memory_store); -} - -int is_const ( memory_space_t space ) -{ - return((space.get_type() == const_space) || (space == param_space_kernel)); -} - -int is_local ( memory_space_t space ) -{ - return (space == local_space) || (space == param_space_local); -} - - void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) { for ( unsigned t=0; t < m_config->warp_size; t++ ) { @@ -730,7 +693,7 @@ void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) m_thread[tid].m_functional_model_thread_state->ptx_exec_inst(inst,t); if( inst.has_callback(t) ) m_warp[inst.warp_id()].inc_n_atomic(); - if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst))) + if (inst.space.is_local() && (inst.is_load() || inst.is_store())) inst.set_addr(t, translate_local_memaddr(inst.get_addr(t), tid, m_gpu->num_shader()) ); if ( ptx_thread_done(tid) ) { m_warp[inst.warp_id()].inc_n_completed(); @@ -763,7 +726,6 @@ void shader_core_ctx::decode_new() unsigned checked=0; unsigned issued=0; while( !m_warp[warp_id].waiting() && !m_warp[warp_id].ibuffer_empty() && (checked < 2) && (issued < 2) ) { - unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask(); const warp_inst_t *pI = m_warp[warp_id].ibuffer_next_inst(); bool valid = m_warp[warp_id].ibuffer_next_valid(); unsigned pc,rpc; @@ -775,9 +737,10 @@ void shader_core_ctx::decode_new() m_warp[warp_id].set_next_pc(pc); m_warp[warp_id].ibuffer_flush(); } else if ( !m_scoreboard->checkCollision(warp_id, pI) ) { + unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask(); assert( m_warp[warp_id].inst_in_pipeline() ); - if ( (pI->op != SFU_OP) && m_pipeline_reg[ID_OC]->empty() ) { - issue_warp(m_pipeline_reg[ID_OC],pI,active_mask,warp_id); + if ( (pI->op != SFU_OP) && m_pipeline_reg[ID_OC_SP]->empty() ) { + issue_warp(m_pipeline_reg[ID_OC_SP],pI,active_mask,warp_id); issued++; } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && m_pipeline_reg[ID_OC_SFU]->empty() ) { issue_warp(m_pipeline_reg[ID_OC_SFU],pI,active_mask,warp_id); @@ -832,30 +795,30 @@ address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, in ///////////////////////////////////////////////////////////////////////////////////////// -void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage ) +void shader_core_ctx::execute_pipe( unsigned current_stage, unsigned next_stage ) { - if( !m_pipeline_reg[next_stage]->empty() ) - return; - if( m_pipeline_reg[pipeline]->cycles > 1 ) { - m_pipeline_reg[pipeline]->cycles--; - return; + if( !m_pipeline_reg[current_stage]->empty() ) { + if( m_pipeline_reg[current_stage]->cycles > 1 ) { + m_pipeline_reg[current_stage]->cycles--; + return; + } } - move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]); - m_shader_memory_new_instruction_processed = false; + if( m_pipeline_reg[next_stage]->empty() ) + move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[current_stage]); } void shader_core_ctx::execute() { - execute_pipe(OC_EX_SFU, EX_MM); - execute_pipe(ID_EX, EX_MM); + execute_pipe(OC_EX_SFU,EX_MM); + execute_pipe(OC_EX_SP,EX_MM); } -mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* warp) +mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* pinst) { // creates an mshr based on the access struct information - mshr_entry* mshr = alloc_free_mshr(access.space == tex_space); - mshr->init(access.addr,access.iswrite,access.space,warp->warp_id()); - warp_inst_t inst = *warp; + mshr_entry* mshr = alloc_free_mshr(pinst->space == tex_space); + mshr->init(access.addr,pinst->is_store(),pinst->space,pinst->warp_id()); + warp_inst_t inst = *pinst; inst.set_active(access.warp_indices); mshr->add_inst(inst); if( m_shader_config->gpgpu_interwarp_mshr_merge ) { @@ -878,7 +841,7 @@ address_type line_size_based_tag_func(address_type address, unsigned line_size) address_type null_tag_func(address_type address, unsigned line_size) { - return address; //no modification: each address is its own tag. Equivalent to line_size_based_tag_func(address,1), but line_size ignored. + return address; //no modification: each address is its own tag. } // only 1 bank @@ -906,172 +869,155 @@ typedef address_type (*tag_func_t)(address_type add, unsigned line_size); void shader_core_ctx::get_memory_access_list( shader_core_ctx::bank_func_t bank_func, tag_func_t tag_func, - memory_pipe_t mem_pipe, unsigned warp_parts, unsigned line_size, bool limit_broadcast, - std::vector &accessq ) + warp_inst_t &inst ) { - const warp_inst_t* insns = m_pipeline_reg[EX_MM]; // Calculates memory accesses generated by this warp // Returns acesses which are "coalesced" // Does not coalesce nor overlap bank accesses across warp "parts". + // This is called once per warp_inst_t when the warp_inst_t enters the memory stage. + // It produces the set of distinct memory accesses that need to be peformed. + // These accessess are then performed over multiple cycles (stalling the pipeline) + // if the accessses cannot be performed all at once. - // This is called once per warp when it enters the memory stage. - // It takes the warp and produces a queue of accesses that can be peformed. - // These are then performed over multiple cycles (stalling the pipeline) if the accessses cannot be - // performed all at once. - // It is a convenience for simulation; in hardware the warp would be processed each cycle - // until it was done. Each cycle would do the first accesses available to it and mark off the - // those threads served by those accesses. - - // Because it calculates all the accesses at once, what follows is largely not as the hw would do it. - // Accesses are assigned an order number based on when that access may be issued. + // Below, accesses are assigned an "order" based on when that access may be issued. // Accesses with the same order number may occur at the same time: they are to different banks. - // Later when the queue is processed it will evaluate accesses of - // as many orders as ports on that cache/shmem. - // These accesses are placed into a queue and sorted so that accesses of the same order are next to each other. - + // Later, when the queue is processed it will evaluate accesses of as many orders as + // ports on that cache/shmem. + // + // Accesses are placed in accessq sorted so that accesses of the same order are adjacent. - // tracks bank accesses for sorting into generations; + // bank_accs tracks bank accesses for sorting into generations; // each entry is (bank #, number of accesses) // the idea is that you can only access a bank a number of times each cycle equal to // its number of ports in one cycle. std::map bank_accs; - //keep track of broadcasts with unique orders if limit_broadcast - //the normally calculated orders will never be greater than warp_size + // keep track of broadcasts with unique orders if limit_broadcast + // the normally calculated orders will never be greater than warp_size unsigned broadcast_order = m_config->warp_size; - unsigned qbegin = accessq.size(); + unsigned qbegin = inst.get_accessq_size(); unsigned qpartbegin = qbegin; unsigned mem_pipe_size = m_config->warp_size / warp_parts; for (unsigned part = 0; part < m_config->warp_size; part += mem_pipe_size) { for (unsigned i = part; i < part + mem_pipe_size; i++) { - if ( !insns->active(i) ) + if ( !inst.active(i) ) continue; - if( insns->space == undefined_space ) - continue; // this happens when thread predicated off - new_addr_type addr = insns->get_addr(i); + assert( inst.space != undefined_space ); + new_addr_type addr = inst.get_addr(i); address_type lane_segment_address = tag_func(addr, line_size); unsigned quarter = 0; if( line_size>=4 ) quarter = (addr / (line_size/4)) & 3; bool match = false; - if( !insns->isatomic() ) { //atomics must have own request - for (unsigned j = qpartbegin; j < accessq.size(); j++) { - if (lane_segment_address == accessq[j].addr) { - assert( not accessq[j].isatomic ); - accessq[j].quarter_count[quarter]++; - accessq[j].warp_indices.push_back(i); + if( !inst.isatomic() ) { //atomics must have own request + for( unsigned j = qpartbegin; j space != undefined_space ); - accessq.push_back( mem_access_t( lane_segment_address, - insns->space, - mem_pipe, - insns->isatomic(), - is_store(*insns), - line_size, quarter, i) ); + if (!match) { // does not match a previous request by another thread, so need a new request + assert( inst.space != undefined_space ); + inst.accessq_push_back( mem_access_t( lane_segment_address, line_size, quarter, i) ); // Determine Bank Conflicts: - unsigned bank = (this->*bank_func)(insns->get_addr(i), line_size); + unsigned bank = (this->*bank_func)(inst.get_addr(i), line_size); // ensure no concurrent bank access accross warp parts. // ie. order will be less than part for all previous loads in previous parts, so: if (bank_accs[bank] < part) bank_accs[bank]=part; - accessq.back().order = bank_accs[bank]; + inst.accessq_back().order = bank_accs[bank]; bank_accs[bank]++; } } - qpartbegin = accessq.size(); //don't coalesce accross warp parts + qpartbegin = inst.get_accessq_size(); //don't coalesce accross warp parts } - //sort requests into order according to order (orders will not necessarily be consequtive if multiple parts) - std::stable_sort(accessq.begin()+qbegin,accessq.end()); + //sort requests by order they will be processed in + inst.sort_accessq(qbegin); } -void shader_core_ctx::memory_shared_process_warp() +void shader_core_ctx::memory_shared_process_warp(warp_inst_t &inst) { // initial processing of shared memory warps get_memory_access_list(&shader_core_ctx::shmem_bank_func, null_tag_func, - SHARED_MEM_PATH, m_config->gpgpu_shmem_pipe_speedup, 1, //shared memory doesn't care about line_size, needs to be at least 1; - true, // limit broadcasts to single cycle. - m_memory_queue.shared); + true, + inst); // limit broadcasts to single cycle. } -void shader_core_ctx::memory_const_process_warp() +void shader_core_ctx::memory_const_process_warp(warp_inst_t &inst) { // initial processing of const memory warps - std::vector &accessq = m_memory_queue.constant; - unsigned qbegin = accessq.size(); + unsigned qbegin = inst.get_accessq_size(); get_memory_access_list( &shader_core_ctx::null_bank_func, line_size_based_tag_func, - CONSTANT_MEM_PATH, 1, //warp parts - m_L1C->get_line_sz(), false, //no broadcast limit. - accessq); + m_L1C->get_line_sz(), + false, //no broadcast limit. + inst); // do cache checks here for each request (non-physical), could be // done later for more accurate timing of cache accesses, but probably uneccesary; - for (unsigned i = qbegin; i < accessq.size(); i++) { - if ( accessq[i].space == param_space_kernel ) { - accessq[i].cache_hit = true; + for (unsigned i = qbegin; i < inst.get_accessq_size(); i++) { + mem_access_t &req = inst.accessq(i); + if ( inst.space == param_space_kernel ) { + req.cache_hit = true; } else { - cache_request_status status = m_L1C->access( accessq[i].addr, + cache_request_status status = m_L1C->access( req.addr, 0, //should always be a read gpu_sim_cycle+gpu_tot_sim_cycle, NULL/*should never writeback*/); - accessq[i].cache_hit = (status == HIT); - if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; - if (accessq[i].cache_hit) m_stats->L1_const_miss++; + req.cache_hit = (status == HIT); + if (m_config->gpgpu_perfect_mem) req.cache_hit = true; + if (req.cache_hit) m_stats->L1_const_miss++; } - accessq[i].cache_checked = true; + req.cache_checked = true; } } -void shader_core_ctx::memory_texture_process_warp() +void shader_core_ctx::memory_texture_process_warp(warp_inst_t &inst) { // initial processing of shared texture warps - std::vector &accessq = m_memory_queue.texture; - unsigned qbegin = accessq.size(); + unsigned qbegin = inst.get_accessq_size(); get_memory_access_list(&shader_core_ctx::null_bank_func, &line_size_based_tag_func, - TEXTURE_MEM_PATH, 1, //warp parts - m_L1T->get_line_sz(), - false, //no broadcast limit. - accessq); + m_L1T->get_line_sz(), + false, //no broadcast limit. + inst); // do cache checks here for each request (non-hardware), could be done later // for more accurate timing of cache accesses, but probably uneccesary; - for (unsigned i = qbegin; i < accessq.size(); i++) { - cache_request_status status = m_L1T->access( accessq[i].addr, + for (unsigned i = qbegin; i < inst.get_accessq_size(); i++) { + mem_access_t &req = inst.accessq(i); + cache_request_status status = m_L1T->access( req.addr, 0, //should always be a read gpu_sim_cycle+gpu_tot_sim_cycle, NULL /*should never writeback*/); - accessq[i].cache_hit = (status == HIT); - if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; - if (accessq[i].cache_hit) m_stats->L1_texture_miss++; - accessq[i].cache_checked = true; + req.cache_hit = (status == HIT); + if (m_config->gpgpu_perfect_mem) req.cache_hit = true; + if (req.cache_hit) m_stats->L1_texture_miss++; + req.cache_checked = true; } } -void shader_core_ctx::memory_global_process_warp() +void shader_core_ctx::memory_global_process_warp( warp_inst_t &inst ) { - std::vector &accessq = m_memory_queue.local_global; - unsigned qbegin = accessq.size(); + unsigned qbegin = inst.get_accessq_size(); unsigned warp_parts = 1; unsigned line_size = m_L1D->get_line_sz(); if (m_config->gpgpu_coalesce_arch == 13) { warp_parts = 2; if(m_config->gpgpu_no_dl1) { - unsigned data_size = m_pipeline_reg[EX_MM]->data_size; + unsigned data_size = inst.data_size; // line size is dependant on instruction; switch (data_size) { case 1: line_size = 32; break; @@ -1083,43 +1029,41 @@ void shader_core_ctx::memory_global_process_warp() } get_memory_access_list( &shader_core_ctx::dcache_bank_func, &line_size_based_tag_func, - GLOBAL_MEM_PATH, warp_parts, line_size, false, - accessq); + inst ); // Now that we have the accesses, if we don't have a cache we can adjust request sizes to // include only the data referenced by the threads - for (unsigned i = qbegin; i < accessq.size(); i++) { + for (unsigned i = qbegin; i < inst.get_accessq_size(); i++) { if (m_config->gpgpu_coalesce_arch == 13 and m_config->gpgpu_no_dl1) { //if there is no l1 cache it makes sense to do coalescing here. //reduce memory request sizes. - char* quarter_counts = accessq[i].quarter_count; + char* quarter_counts = inst.accessq(i).quarter_count; bool low = quarter_counts[0] or quarter_counts[1]; bool high = quarter_counts[2] or quarter_counts[3]; - if (accessq[i].req_size == 128) { + if (inst.accessq(i).req_size == 128) { if (low xor high) { //can reduce size - accessq[i].req_size = 64; - if (high) accessq[i].addr += 64; + inst.accessq(i).req_size = 64; + if (high) inst.accessq(i).addr += 64; low = quarter_counts[0] or quarter_counts[2]; //set low and high for next pass high = quarter_counts[1] or quarter_counts[3]; } } - if (accessq[i].req_size == 64) { + if (inst.accessq(i).req_size == 64) { if (low xor high) { //can reduce size - accessq[i].req_size = 32; - if (high) accessq[i].addr += 32; + inst.accessq(i).req_size = 32; + if (high) inst.accessq(i).addr += 32; } } } } } -mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) +mem_stage_stall_type shader_core_ctx::send_mem_request(warp_inst_t &inst, mem_access_t &access) { // Attempt to send an request/write to memory based on information in access. - warp_inst_t* warp = m_pipeline_reg[EX_MM]; // If the cache told us it needed to write back a dirty line, do this now // It is possible to do this writeback in the same cycle as the access request, this may not be realistic. @@ -1130,63 +1074,64 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) return WB_ICNT_RC_FAIL; } fq_push( access.wb_addr, req_size, true, NO_PARTIAL_WRITE, -1, NULL, - is_local(access.space)?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request + inst.space.is_local()?LOCAL_ACC_W:GLOBAL_ACC_W, //space of cache line is same as new request -1); m_stats->L1_writeback++; access.need_wb = false; } + + bool is_write = inst.is_store(); mem_access_type access_type; - switch(access.space.get_type()) { + switch(inst.space.get_type()) { case const_space: case param_space_kernel: access_type = CONST_ACC_R; break; case tex_space: access_type = TEXTURE_ACC_R; break; - case global_space: access_type = (access.iswrite)? GLOBAL_ACC_W: GLOBAL_ACC_R; break; + case global_space: access_type = is_write? GLOBAL_ACC_W: GLOBAL_ACC_R; break; case local_space: - case param_space_local: access_type = (access.iswrite)? LOCAL_ACC_W: LOCAL_ACC_R; break; + case param_space_local: access_type = is_write? LOCAL_ACC_W: LOCAL_ACC_R; break; default: assert(0); break; } //reserve mshr - bool requires_mshr = (not access.iswrite); - if (requires_mshr and not access.reserved_mshr) { + bool requires_mshr = (!is_write); + if (requires_mshr && !access.reserved_mshr) { if (not m_mshr_unit->has_mshr(1)) return MSHR_RC_FAIL; - access.reserved_mshr = m_mshr_unit->add_mshr(access, warp); + access.reserved_mshr = m_mshr_unit->add_mshr(access, &inst); access.recheck_cache = false; //we have an mshr now, so have checked cache in same cycle as checking mshrs, so have merged if necessary. } //require inct if access is this far without reserved mshr, or has and mshr but not merged with another request - bool requires_icnt = (not access.reserved_mshr) or (not access.reserved_mshr->ismerged() ); + bool requires_icnt = (!access.reserved_mshr) || (!access.reserved_mshr->ismerged()); if (requires_icnt) { //calculate request size for icnt check (and later send); unsigned request_size = access.req_size; - if (access.iswrite) { + if (is_write) { if (requires_mshr) request_size += READ_PACKET_SIZE + WRITE_MASK_SIZE; // needs information for a load back into cache. else request_size += WRITE_PACKET_SIZE + WRITE_MASK_SIZE; //plain write } - if ( !m_gpu->fq_has_buffer(access.addr, request_size, access.iswrite, m_sid) ) { + if ( !m_gpu->fq_has_buffer(access.addr, request_size, is_write, m_sid) ) { // can't allocate icnt m_stats->gpu_stall_sh2icnt++; return ICNT_RC_FAIL; } //send over interconnect partial_write_mask_t write_mask = NO_PARTIAL_WRITE; - unsigned warp_id = warp->warp_id(); - if (access.iswrite) { - if (!strcmp("GT200",m_config->pipeline_model) ) - m_warp[warp_id].inc_store_req(); + unsigned warp_id = inst.warp_id(); + if (is_write) { + m_warp[warp_id].inc_store_req(); for (unsigned i=0;i < access.warp_indices.size();i++) { unsigned w = access.warp_indices[i]; - int data_offset = warp->get_addr(w) & ((unsigned long long int)access.req_size - 1); - for (unsigned b = data_offset; b < data_offset + warp->data_size; b++) write_mask.set(b); + int data_offset = inst.get_addr(w) & ((unsigned long long int)access.req_size - 1); + for (unsigned b = data_offset; b < data_offset + inst.data_size; b++) write_mask.set(b); } if (write_mask.count() != access.req_size) m_stats->gpgpu_n_partial_writes++; } fq_push( access.addr, request_size, - access.iswrite, write_mask, warp_id , access.reserved_mshr, - access_type, warp->pc ); + is_write, write_mask, warp_id , access.reserved_mshr, + access_type, inst.pc ); } return NO_RC_FAIL; } @@ -1206,32 +1151,33 @@ void shader_core_ctx::writeback() move_warp(m_pipeline_reg[WB_RT],m_pipeline_reg[MM_WB]); } -bool shader_core_ctx::memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) +bool shader_core_ctx::memory_shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { // Process a single cycle of activity from the shared memory queue. + if( inst.space.get_type() != shared_space ) + return true; - std::vector &accessq = m_memory_queue.shared; //consume port number orders from the top of the queue; - for (int i = 0; i < m_config->gpgpu_shmem_port_per_bank; i++) { - if (accessq.empty()) + for( int i = 0; i < m_config->gpgpu_shmem_port_per_bank; i++ ) { + if (inst.accessq_empty()) break; - unsigned current_order = accessq.back().order; + unsigned current_order = inst.accessq_back().order; //consume all requests of the same order (concurrent bank requests) - while ((not accessq.empty()) and accessq.back().order == current_order) - accessq.pop_back(); + while ((!inst.accessq_empty()) && inst.accessq_back().order == current_order) + inst.accessq_pop_back(); } - if (not accessq.empty()) { + if( !inst.accessq_empty() ) { rc_fail = BK_CONF; fail_type = S_MEM; m_stats->gpgpu_n_shmem_bkconflict++; } - return accessq.empty(); //done if empty. + return inst.accessq_empty(); //done if empty. } mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_ctx::cache_check_t cache_check, unsigned ports_per_bank, unsigned memory_send_max, - std::vector &accessq ) + warp_inst_t &inst ) { // Generic algorithm for processing a single cycle of accesses for the memory space types that go to L2 or DRAM. @@ -1239,42 +1185,42 @@ mem_stage_stall_type shader_core_ctx::process_memory_access_queue( shader_core_c mem_stage_stall_type hazard_cond = NO_RC_FAIL; unsigned mem_req_count = 0; // number of requests to sent to memory this cycle for (unsigned i = 0; i < ports_per_bank; i++) { - if (accessq.empty()) + if (inst.accessq_empty()) break; - unsigned current_order = accessq.back().order; + unsigned current_order = inst.accessq_back().order; // consume all requests of the same "order" but stop if we hit a structural hazard - while ((not accessq.empty()) and accessq.back().order == current_order and hazard_cond == NO_RC_FAIL) { - hazard_cond = (this->*cache_check)(accessq.back()); + while ((!inst.accessq_empty()) && inst.accessq_back().order == current_order && hazard_cond == NO_RC_FAIL) { + hazard_cond = (this->*cache_check)(inst,inst.accessq_back()); if (hazard_cond != NO_RC_FAIL) break; // can't complete this request this cycle. - if (not accessq.back().cache_hit){ + if (! inst.accessq_back().cache_hit){ if (mem_req_count < memory_send_max) { mem_req_count++; - hazard_cond = send_mem_request(accessq.back()); // attemp to get mshr, icnt, send; + hazard_cond = send_mem_request(inst,inst.accessq_back()); // attemp to get mshr, icnt, send; } else hazard_cond = COAL_STALL; // not really a coal stall, its a too many memory request stall; if ( hazard_cond != NO_RC_FAIL) break; //can't complete this request this cycle. } - accessq.pop_back(); + inst.accessq_pop_back(); } } - if (not accessq.empty() and hazard_cond == NO_RC_FAIL) { + if (!inst.accessq_empty() && hazard_cond == NO_RC_FAIL) { //no resource failed so must be a bank comflict. hazard_cond = BK_CONF; } return hazard_cond; } -bool shader_core_ctx::memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) +bool shader_core_ctx::memory_constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { - // Process a single cycle of activity from the the constant memory queue. - - std::vector &accessq = m_memory_queue.constant; + if( (inst.space.get_type() != const_space) && (inst.space.get_type() != param_space_kernel) ) + return true; + // Process a single cycle of activity from the the constant memory queue. mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::ccache_check, m_config->gpgpu_const_port_per_bank, 1, //memory send max per cycle - accessq ); + inst ); if (fail != NO_RC_FAIL){ rc_fail = fail; //keep other fails if this didn't fail. fail_type = C_MEM; @@ -1282,37 +1228,39 @@ bool shader_core_ctx::memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_ m_stats->gpgpu_n_cmem_portconflict++; //coal stalls aren't really a bank conflict, but this maintains previous behavior. } } - return accessq.empty(); //done if empty. + return inst.accessq_empty(); //done if empty. } -bool shader_core_ctx::memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) +bool shader_core_ctx::memory_texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { + if( inst.space.get_type() != tex_space ) + return true; + // Process a single cycle of activity from the the texture memory queue. - std::vector &accessq = m_memory_queue.texture; mem_stage_stall_type fail = process_memory_access_queue(&shader_core_ctx::tcache_check, 1, //how is tex memory banked? 1, //memory send max per cycle - accessq ); + inst ); if (fail != NO_RC_FAIL){ rc_fail = fail; //keep other fails if this didn't fail. fail_type = T_MEM; } - return accessq.empty(); //done if empty. + return inst.accessq_empty(); //done if empty. } -mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) +mem_stage_stall_type shader_core_ctx::dcache_check(warp_inst_t &inst, mem_access_t& access) { // Global memory (data cache) checks the cache for each access at the time it is processed. // This is more accurate to hardware, and necessary for proper action of the writeback cache. - if (access.cache_checked and not access.recheck_cache) + if (access.cache_checked && !access.recheck_cache) return NO_RC_FAIL; if (!m_config->gpgpu_no_dl1 && !m_config->gpgpu_perfect_mem) { //check cache cache_request_status status = m_L1D->access( access.addr, - access.iswrite, + inst.is_store(), gpu_sim_cycle+gpu_tot_sim_cycle, &access.wb_addr ); if (status == RESERVATION_FAIL) { @@ -1321,7 +1269,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) } access.cache_hit = (status == HIT); //if HIT_W_WT then still send to memory so "MISS" if (status == MISS_W_WB) access.need_wb = true; - if (status == WB_HIT_ON_MISS and access.iswrite) + if (status == WB_HIT_ON_MISS && inst.is_store()) { //write has hit a reserved cache line //it has writen its data into the cache line, so no need to go to memory @@ -1333,7 +1281,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) // MSHR will still forward the unmasked value to its dependant reads. // if doing stall on use, must stall this thread after this write (otherwise, inproper values may be forwarded to future reads). } - if (status == WB_HIT_ON_MISS and not access.iswrite) { + if (status == WB_HIT_ON_MISS && !inst.is_store() ) { //read has hit on a reserved cache line, //we need to make sure cache check happens on same cycle as a mshr merge happens, otherwise we might miss it coming back access.recheck_cache = true; @@ -1343,12 +1291,13 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) access.cache_hit = false; } - if (m_config->gpgpu_perfect_mem) access.cache_hit = true; + if (m_config->gpgpu_perfect_mem) + access.cache_hit = true; - if (access.isatomic) { + if (inst.isatomic()) { if (m_config->gpgpu_perfect_mem) { // complete functional execution of atomic here - m_pipeline_reg[EX_MM]->do_atomic(); + inst.do_atomic(); } else { // atomics always go to memory access.cache_hit = false; @@ -1356,63 +1305,65 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) } if (!access.cache_hit) { - if (access.iswrite) m_stats->L1_write_miss++; + if (inst.is_store()) m_stats->L1_write_miss++; else m_stats->L1_read_miss++; } return NO_RC_FAIL; } -bool shader_core_ctx::memory_cycle( mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type) +bool shader_core_ctx::memory_cycle( warp_inst_t &inst, mem_stage_stall_type &stall_reason, mem_stage_access_type &access_type ) { - // Process a single cycle of activity from the the global/local memory queue. - - std::vector &accessq = m_memory_queue.local_global; - mem_stage_stall_type stall_cond = process_memory_access_queue(&shader_core_ctx::dcache_check, m_config->gpgpu_cache_port_per_bank, 1, accessq); + if( (inst.space.get_type() != global_space) && + (inst.space.get_type() != local_space) && + (inst.space.get_type() != param_space_local) ) + return true; + // Process a single cycle of activity from the the global/local memory queue. + mem_stage_stall_type stall_cond = process_memory_access_queue(&shader_core_ctx::dcache_check,m_config->gpgpu_cache_port_per_bank,1,inst); if (stall_cond != NO_RC_FAIL) { stall_reason = stall_cond; - bool iswrite = accessq.back().iswrite; - if (is_local(accessq.back().space)) + bool iswrite = inst.is_store(); + if (inst.space.is_local()) access_type = (iswrite)?L_MEM_ST:L_MEM_LD; else access_type = (iswrite)?G_MEM_ST:G_MEM_LD; - if (stall_cond == BK_CONF or stall_cond == COAL_STALL) + if (stall_cond == BK_CONF || stall_cond == COAL_STALL) m_stats->gpgpu_n_cache_bkconflict++; } - return accessq.empty(); //done if empty. + return inst.accessq_empty(); //done if empty. } -void shader_core_ctx::memory_queue() +void shader_core_ctx::memory_queue( warp_inst_t &pipe_reg ) { // Called once per warp when warp enters memory stage. // Generates a list of memory accesses, but does not perform the memory access. - - if( m_pipeline_reg[EX_MM]->empty() ) + if( pipe_reg.empty() ) return; - m_gpu->mem_instruction_stats(m_pipeline_reg[EX_MM]); - switch( m_pipeline_reg[EX_MM]->space.get_type() ) { - case shared_space: memory_shared_process_warp(); break; - case tex_space: memory_texture_process_warp(); break; - case const_space: case param_space_kernel: memory_const_process_warp(); break; - case global_space: case local_space: case param_space_local: memory_global_process_warp(); break; + if( pipe_reg.mem_accesses_computed() ) + return; + m_gpu->mem_instruction_stats(pipe_reg); + switch( pipe_reg.space.get_type() ) { + case shared_space: memory_shared_process_warp(pipe_reg); break; + case tex_space: memory_texture_process_warp(pipe_reg); break; + case const_space: case param_space_kernel: memory_const_process_warp(pipe_reg); break; + case global_space: case local_space: case param_space_local: memory_global_process_warp(pipe_reg); break; case param_space_unclassified: abort(); break; default: break; // non-memory operations } + pipe_reg.set_mem_accesses_computed(); } void shader_core_ctx::memory() { - if (!m_shader_memory_new_instruction_processed) { - m_shader_memory_new_instruction_processed = true; // do once per warp instruction - memory_queue(); - } + warp_inst_t &pipe_reg = *m_pipeline_reg[EX_MM]; + memory_queue(pipe_reg); bool done = true; enum mem_stage_stall_type rc_fail = NO_RC_FAIL; mem_stage_access_type type; - done &= memory_shared_cycle(rc_fail, type); - done &= memory_constant_cycle(rc_fail, type); - done &= memory_texture_cycle(rc_fail, type); - done &= memory_cycle(rc_fail, type); + done &= memory_shared_cycle(pipe_reg, rc_fail, type); + done &= memory_constant_cycle(pipe_reg, rc_fail, type); + done &= memory_texture_cycle(pipe_reg, rc_fail, type); + done &= memory_cycle(pipe_reg, rc_fail, type); m_mem_rc = rc_fail; if (!done) { // log stall types and return assert(rc_fail != NO_RC_FAIL); @@ -1420,7 +1371,7 @@ void shader_core_ctx::memory() m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++; return; } - if( not m_pipeline_reg[MM_WB]->empty() ) + if( !m_pipeline_reg[MM_WB]->empty() ) return; // writeback stalled move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]); } @@ -1579,52 +1530,37 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed); fprintf(fout, "=================================================\n"); - if (!strcmp("GT200",m_config->pipeline_model) ) { - dump_istream_state(fout); - fprintf(fout,"\n"); + dump_istream_state(fout); + fprintf(fout,"\n"); - fprintf(fout, "IF/ID = "); - if( !m_inst_fetch_buffer.m_valid ) - fprintf(fout,"bubble\n"); - else { - fprintf(fout,"w%2u : pc = 0x%x, nbytes = %u\n", - m_inst_fetch_buffer.m_warp_id, - m_inst_fetch_buffer.m_pc, - m_inst_fetch_buffer.m_nbytes ); - } - fprintf(fout,"\nibuffer status:\n"); - for( unsigned i=0; imax_warps_per_shader; i++) { - if( !m_warp[i].ibuffer_empty() ) - m_warp[i].print_ibuffer(fout); - } - fprintf(fout,"\n"); - display_pdom_state(fout,mask); + fprintf(fout, "IF/ID = "); + if( !m_inst_fetch_buffer.m_valid ) + fprintf(fout,"bubble\n"); + else { + fprintf(fout,"w%2u : pc = 0x%x, nbytes = %u\n", + m_inst_fetch_buffer.m_warp_id, + m_inst_fetch_buffer.m_pc, + m_inst_fetch_buffer.m_nbytes ); } + fprintf(fout,"\nibuffer status:\n"); + for( unsigned i=0; imax_warps_per_shader; i++) { + if( !m_warp[i].ibuffer_empty() ) + m_warp[i].print_ibuffer(fout); + } + fprintf(fout,"\n"); + display_pdom_state(fout,mask); m_scoreboard->printContents(); - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - if ( mask & 0x20 ) { - fprintf(fout, "TS/IF = "); - print_stage(TS_IF, fout, print_mem, mask); - } - fprintf(fout, "IF/ID = "); - print_stage(IF_ID, fout, print_mem, mask ); - } - if (m_config->gpgpu_operand_collector) { - fprintf(fout,"ID/OC (SP) = "); - print_stage(ID_OC, fout, print_mem, mask); - fprintf(fout,"ID/OC (SFU) = "); - print_stage(ID_OC_SFU, fout, print_mem, mask); - m_operand_collector.dump(fout); - } - if (!strcmp("GT200",m_config->pipeline_model) ) - fprintf(fout, "ID/EX (SP) = "); - print_stage(ID_EX, fout, print_mem, mask); - if (!strcmp("GT200",m_config->pipeline_model) ) { - fprintf(fout, "ID/EX (SFU) = "); - print_stage(OC_EX_SFU, fout, print_mem, mask); - } + fprintf(fout,"ID/OC (SP) = "); + print_stage(ID_OC_SP, fout, print_mem, mask); + fprintf(fout,"ID/OC (SFU) = "); + print_stage(ID_OC_SFU, fout, print_mem, mask); + m_operand_collector.dump(fout); + fprintf(fout, "ID/EX (SP) = "); + print_stage(OC_EX_SP, fout, print_mem, mask); + fprintf(fout, "ID/EX (SFU) = "); + print_stage(OC_EX_SFU, fout, print_mem, mask); fprintf(fout, "EX/MEM = "); print_stage(EX_MM, fout, print_mem, mask); if( m_mem_rc != NO_RC_FAIL ) { @@ -1702,7 +1638,7 @@ void shader_core_ctx::cycle_gt200() writeback(); memory(); execute(); - m_operand_collector.step(m_pipeline_reg[ID_OC],m_pipeline_reg[ID_OC_SFU]); + m_operand_collector.step(m_pipeline_reg[ID_OC_SP],m_pipeline_reg[ID_OC_SFU]); decode_new(); fetch_new(); } @@ -2101,8 +2037,8 @@ void mshr_entry::init( new_addr_type address, bool wr, memory_space_t space, uns m_merged_requests =NULL; m_iswrite = wr; m_isinst = space==instruction_space; - m_islocal = is_local(space); - m_isconst = is_const(space); + m_islocal = space.is_local(); + m_isconst = space.is_const(); m_istexture = space==tex_space; m_insts.clear(); m_warp_id = warp_id; diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index a9e27b8..8e98749 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -792,84 +792,6 @@ private: warp_set_t m_warp_at_barrier; }; -class warp_tracker; -class warp_tracker_pool; - -enum memory_pipe_t { - NO_MEM_PATH = 0, - SHARED_MEM_PATH, - GLOBAL_MEM_PATH, - TEXTURE_MEM_PATH, - CONSTANT_MEM_PATH, - NUM_MEM_PATHS //not a mem path -}; - -class mem_access_t { -public: - mem_access_t() : space(undefined_space) - { - init(); - } - mem_access_t(address_type a, memory_space_t s, memory_pipe_t p, bool atomic, bool w, unsigned r, unsigned quarter, unsigned idx ) - { - init(); - addr = a; - space = s; - mem_pipe = p; - isatomic = atomic; - iswrite = w; - req_size = r; - quarter_count[quarter]++; - warp_indices.push_back(idx); - } - - bool operator<(const mem_access_t &other) const {return (order > other.order);}//this is reverse - -private: - void init() - { - uid=++next_access_uid; - addr=0; - req_size=0; - order=0; - _quarter_count_all=0; - mem_pipe = NO_MEM_PATH; - isatomic = false; - cache_hit = false; - cache_checked = false; - recheck_cache = false; - iswrite = false; - need_wb = false; - wb_addr = 0; - reserved_mshr = NULL; - } - -public: - - unsigned uid; - address_type addr; //address of the segment to load. - unsigned req_size; //bytes - unsigned order; // order of accesses, based on banks. - union{ - unsigned _quarter_count_all; - char quarter_count[4]; //access counts to each quarter of segment, for compaction; - }; - std::vector warp_indices; // warp indicies for this request. - memory_space_t space; - memory_pipe_t mem_pipe; - bool isatomic; - bool cache_hit; - bool cache_checked; - bool recheck_cache; - bool iswrite; - bool need_wb; - address_type wb_addr; // writeback address (if necessary). - mshr_entry* reserved_mshr; - -private: - static unsigned next_access_uid; -}; - class mshr_lookup { public: mshr_lookup( const struct shader_core_config *config ) { m_shader_config = config; } @@ -900,7 +822,7 @@ public: //return queue pop; (includes texture pipeline return) void pop_return_head(); - mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* warp); + mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* inst); void mshr_return_from_mem(mshr_entry *mshr); unsigned get_max_mshr_used() const {return m_max_mshr_used;} void print(FILE* fp, class shader_core_ctx* shader,unsigned mask); @@ -927,13 +849,6 @@ private: mshr_lookup m_mshr_lookup; }; -struct shader_queues_t { - std::vector shared; - std::vector constant; - std::vector texture; - std::vector local_global; -}; - struct insn_latency_info { unsigned pc; unsigned long latency; @@ -956,20 +871,6 @@ struct ifetch_buffer_t { unsigned m_warp_id; }; -// Struct for storing warp information in fixeddelay_queue -struct fixeddelay_queue_warp_t { - unsigned long long ready_cycle; - std::vector tids; // list of tid's in this warp (to unlock) - inst_t inst; -}; - -struct fixeddelay_queue_warp_comp { - inline bool operator()(const fixeddelay_queue_warp_t& left,const fixeddelay_queue_warp_t& right) const - { - return left.ready_cycle < right.ready_cycle; - } -}; - typedef address_type (*tag_func_t)(address_type add, unsigned line_size); class shader_core_ctx : public core_t @@ -1050,27 +951,27 @@ private: void execute_pipe( unsigned pipeline, unsigned next_stage ); void memory(); // advance memory pipeline stage - void memory_queue(); - void memory_shared_process_warp(); - void memory_const_process_warp(); - void memory_texture_process_warp(); - void memory_global_process_warp(); - bool memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); - bool memory_constant_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); - bool memory_texture_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); - bool memory_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + void memory_queue(warp_inst_t &pipe_reg); + void memory_shared_process_warp(warp_inst_t &inst); + void memory_const_process_warp(warp_inst_t &inst); + void memory_texture_process_warp(warp_inst_t &inst); + void memory_global_process_warp(warp_inst_t &inst); + bool memory_shared_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + bool memory_constant_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + bool memory_texture_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); + bool memory_cycle( warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); address_type translate_local_memaddr(address_type localaddr, int tid, unsigned num_shader ); - mem_stage_stall_type ccache_check(mem_access_t& access){ return NO_RC_FAIL;} - mem_stage_stall_type tcache_check(mem_access_t& access){ return NO_RC_FAIL;} - mem_stage_stall_type dcache_check(mem_access_t& access); + mem_stage_stall_type ccache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;} + mem_stage_stall_type tcache_check(warp_inst_t &inst, mem_access_t& access){ return NO_RC_FAIL;} + mem_stage_stall_type dcache_check(warp_inst_t &inst, mem_access_t& access); - typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(mem_access_t&); + typedef mem_stage_stall_type (shader_core_ctx::*cache_check_t)(warp_inst_t &,mem_access_t&); mem_stage_stall_type process_memory_access_queue( shader_core_ctx::cache_check_t cache_check, unsigned ports_per_bank, unsigned memory_send_max, - std::vector &accessq ); + warp_inst_t &inst ); typedef int (shader_core_ctx::*bank_func_t)(address_type add, unsigned line_size); @@ -1080,12 +981,11 @@ private: void get_memory_access_list( bank_func_t bank_func, tag_func_t tag_func, - memory_pipe_t mem_pipe, unsigned warp_parts, unsigned line_size, bool limit_broadcast, - std::vector &accessq ); - mem_stage_stall_type send_mem_request(mem_access_t &access); + warp_inst_t &inst ); + mem_stage_stall_type send_mem_request(warp_inst_t &inst, mem_access_t &access); void writeback(); @@ -1129,7 +1029,6 @@ private: Scoreboard *m_scoreboard; opndcoll_rfu_t m_operand_collector; mshr_shader_unit *m_mshr_unit; - shader_queues_t m_memory_queue; // fetch int m_last_warp_fetched; @@ -1140,33 +1039,18 @@ private: cache_t *m_L1T; // texture cache cache_t *m_L1C; // constant cache - bool m_shader_memory_new_instruction_processed; enum mem_stage_stall_type m_mem_rc; }; -void init_mshr_pool(); -mshr_entry* alloc_mshr_entry(); -void free_mshr_entry( mshr_entry * ); - -// print out the accumulative statistics for shaders (those that are not local to one shader) -void shader_print_runtime_stat( FILE *fout ); -void shader_print_l1_miss_stat( FILE *fout ); - -#define TS_IF 0 -#define IF_ID 1 -#define ID_RR 2 -#define ID_EX 3 -#define RR_EX 3 -#define EX_MM 4 -#define MM_WB 5 -#define WB_RT 6 -#define ID_OC 7 -#define ID_OC_SFU 8 -#define OC_EX_SFU 9 -#define N_PIPELINE_STAGES 10 - -extern unsigned int *shader_cycle_distro; - -int is_store ( const inst_t &op ); +enum pipeline_stage_name_t { + ID_OC_SP=0, + ID_OC_SFU, + OC_EX_SP, + OC_EX_SFU, + EX_MM, + MM_WB, + WB_RT, + N_PIPELINE_STAGES +}; #endif /* SHADER_H */ -- cgit v1.3